Skip to content

Commit ab517d3

Browse files
eupharinaresistor
authored andcommitted
[CHERI_CSA] New alpha.cheri.SubObjectRepresentability checker
1 parent 9564540 commit ab517d3

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,4 +1828,10 @@ let ParentPackage = CHERI in {
18281828

18291829
} // end cheri
18301830

1831-
let ParentPackage = CHERIAlpha in {} // end alpha.cheri
1831+
let ParentPackage = CHERIAlpha in {
1832+
1833+
def SubObjectRepresentabilityChecker : Checker<"SubObjectRepresentability">,
1834+
HelpText<"TODO: help">,
1835+
Documentation<NotDocumented>;
1836+
1837+
} // end alpha.cheri
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// ==-- PointerSizeAssumptionsChecker.cpp -------------------------*- C++ -*-=//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This checker detects record fields that will not have precise bounds when
10+
// compiled with
11+
// -cheri-bounds=subobject-safe
12+
// due to big size and underaligned offset, as narrowed capability will not
13+
// be representable
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "clang/AST/StmtVisitor.h"
18+
#include "clang/ASTMatchers/ASTMatchFinder.h"
19+
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
20+
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21+
#include "clang/StaticAnalyzer/Core/Checker.h"
22+
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
23+
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
24+
#include "llvm/ADT/SmallString.h"
25+
#include "llvm/CHERI/CompressedCapability.h"
26+
#include "llvm/Support/raw_ostream.h"
27+
28+
using namespace clang;
29+
using namespace ento;
30+
31+
namespace {
32+
class SubObjectRepresentabilityChecker
33+
: public Checker<check::ASTDecl<RecordDecl>> {
34+
public:
35+
void checkASTDecl(const RecordDecl *R, AnalysisManager &mgr,
36+
BugReporter &BR) const;
37+
};
38+
39+
} // namespace
40+
41+
void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
42+
AnalysisManager &mgr,
43+
BugReporter &BR) const {
44+
if (!R->isCompleteDefinition())
45+
return;
46+
47+
if (!R->getLocation().isValid())
48+
return;
49+
50+
/*
51+
SrcMgr::CharacteristicKind Kind =
52+
BR.getSourceManager().getFileCharacteristic(Location);
53+
// Ignore records in system headers
54+
if (Kind != SrcMgr::C_User)
55+
return;
56+
*/
57+
58+
for (FieldDecl *D : R->fields()) {
59+
QualType T = D->getType();
60+
61+
ASTContext &ASTCtx = BR.getContext();
62+
uint64_t Offset = ASTCtx.getFieldOffset(D) / 8;
63+
if (Offset > 0) {
64+
uint64_t Size = ASTCtx.getTypeSize(T) / 8;
65+
uint64_t ReqAlign = llvm::CompressedCapability::GetRequiredAlignment(
66+
Size, llvm::CompressedCapability::Cheri128)
67+
.value();
68+
if (1 << llvm::countr_zero(Offset) < ReqAlign) {
69+
/* Emit warning */
70+
SmallString<1024> Err;
71+
llvm::raw_svector_ostream OS(Err);
72+
const PrintingPolicy &PP = ASTCtx.getPrintingPolicy();
73+
OS << "Field '";
74+
D->getNameForDiagnostic(OS, PP, false);
75+
OS << "' of type '" << T.getAsString(PP) << "'";
76+
OS << " (size " << Size << ")";
77+
OS << " requires " << ReqAlign << " byte alignment for precise bounds;";
78+
OS << " field offset is " << Offset;
79+
80+
// Note that this will fire for every translation unit that uses this
81+
// class. This is suboptimal, but at least scan-build will merge
82+
// duplicate HTML reports.
83+
PathDiagnosticLocation L =
84+
PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
85+
BR.EmitBasicReport(R, this, "Field with imprecise subobject bounds",
86+
"CHERI portability", OS.str(), L);
87+
}
88+
}
89+
}
90+
}
91+
92+
void ento::registerSubObjectRepresentabilityChecker(CheckerManager &mgr) {
93+
mgr.registerChecker<SubObjectRepresentabilityChecker>();
94+
}
95+
96+
bool ento::shouldRegisterSubObjectRepresentabilityChecker(
97+
const CheckerManager &mgr) {
98+
return true;
99+
}

clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_clang_library(clangStaticAnalyzerCheckers
2929
CHERI/PointerSizeAssumptionsChecker.cpp
3030
CHERI/ProvenanceSourceChecker.cpp
3131
CHERI/CapabilityCopyChecker.cpp
32+
CHERI/SubObjectRepresentabilityChecker.cpp
3233
ChrootChecker.cpp
3334
CloneChecker.cpp
3435
ContainerModeling.cpp
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test for Morello
2+
3+
// XFAIL: *
4+
// RUN: %clang_cc1 -triple aarch64-none-elf -target-feature +morello -target-feature +c64 -target-abi purecap \
5+
// RUN: -analyze -analyzer-checker=core,alpha.cheri.SubObjectRepresentability -verify %s
6+
7+
struct R1 {
8+
struct {
9+
struct {
10+
char c;
11+
char a[0x3FFF]; // no warn
12+
} f1good;
13+
struct {
14+
char c;
15+
char a[0x4000]; // expected-warning{{Field 'a' of type 'char[16384]' (size 16384) requires 8 byte alignment for precise bounds; field offset is 1}}
16+
} f2bad;
17+
struct {
18+
int c[2];
19+
char a[0x4000]; // no warn
20+
} f3good __attribute__((aligned(8)));
21+
} s2;
22+
} s1;

0 commit comments

Comments
 (0)