Skip to content

Commit a7a9fcb

Browse files
eupharinaresistor
authored andcommitted
[CHERI_CSA] SubObjectRepresentability: support other CHERI targets
1 parent 5a4f478 commit a7a9fcb

File tree

2 files changed

+80
-37
lines changed

2 files changed

+80
-37
lines changed

clang/lib/StaticAnalyzer/Checkers/CHERI/SubObjectRepresentabilityChecker.cpp

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ using namespace clang;
3030
using namespace ento;
3131

3232
namespace {
33+
34+
template <llvm::CompressedCapability::CapabilityFormat>
35+
std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D, BugReporter &BR,
36+
const BugType &BT);
37+
3338
class SubObjectRepresentabilityChecker
3439
: public Checker<check::ASTDecl<RecordDecl>, check::ASTCodeBody> {
3540
BugType BT_1{this, "Field with imprecise subobject bounds",
@@ -42,6 +47,23 @@ class SubObjectRepresentabilityChecker
4247
BugReporter &BR) const;
4348
void checkASTCodeBody(const Decl *D, AnalysisManager &mgr,
4449
BugReporter &BR) const;
50+
51+
private:
52+
using CheckFieldFn = std::function<std::unique_ptr<BugReport>(
53+
const FieldDecl *D, BugReporter &BR, const BugType &BT)>;
54+
55+
const std::map<llvm::Triple::ArchType, CheckFieldFn> CheckFieldFnMap = {
56+
//{llvm::Triple::aarch64, &checkFieldImpl<CompressedCap128m>},
57+
{llvm::Triple::mips,
58+
&checkFieldImpl<llvm::CompressedCapability::Cheri64>},
59+
{llvm::Triple::mips64,
60+
&checkFieldImpl<llvm::CompressedCapability::Cheri128>},
61+
{llvm::Triple::riscv32,
62+
&checkFieldImpl<llvm::CompressedCapability::Cheri64>},
63+
{llvm::Triple::riscv64,
64+
&checkFieldImpl<llvm::CompressedCapability::Cheri128>}};
65+
66+
CheckFieldFn getCheckFieldFn(ASTContext &ASTCtx) const;
4567
};
4668

4769
} // namespace
@@ -112,9 +134,8 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D, BugReporter &BR,
112134
uint64_t Offset = ASTCtx.getFieldOffset(D) / 8;
113135
if (Offset > 0) {
114136
uint64_t Size = ASTCtx.getTypeSize(T) / 8;
115-
uint64_t ReqAlign = llvm::CompressedCapability::GetRequiredAlignment(
116-
Size, llvm::CompressedCapability::Cheri128)
117-
.value();
137+
uint64_t ReqAlign =
138+
llvm::CompressedCapability::GetRequiredAlignment(Size, Handler).value();
118139
uint64_t CurAlign = 1 << llvm::countr_zero(Offset);
119140
if (CurAlign < ReqAlign) {
120141
/* Emit warning */
@@ -129,15 +150,14 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D, BugReporter &BR,
129150
OS << " field offset is " << Offset;
130151
OS << " (aligned to " << CurAlign << ");";
131152

132-
#if 0
133-
const RecordDecl *Parent = D->getParent();
134-
uint64_t ParentSize = ASTCtx.getTypeSize(Parent->getTypeForDecl()) / 8;
135-
typename Handler::cap_t MockCap =
136-
getBoundedCap<Handler>(ParentSize, Offset, Size);
137-
uint64_t Base = MockCap.base();
138-
uint64_t Top = MockCap.top();
153+
uint64_t OffsetToAlign = Offset % ReqAlign;
154+
uint64_t Base = Offset - OffsetToAlign;
155+
uint64_t AlignedSize = Size + OffsetToAlign;
156+
uint64_t TailPadding = static_cast<uint64_t>(
157+
llvm::CompressedCapability::GetRequiredTailPadding(AlignedSize,
158+
Handler));
159+
uint64_t Top = Base + AlignedSize + TailPadding;
139160
OS << " Current bounds: " << Base << "-" << Top;
140-
#endif
141161

142162
// Note that this will fire for every translation unit that uses this
143163
// class. This is suboptimal, but at least scan-build will merge
@@ -148,51 +168,41 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D, BugReporter &BR,
148168
Report->setDeclWithIssue(D);
149169
Report->addRange(D->getSourceRange());
150170

151-
#if 0
152171
Report = reportExposedFields(D, ASTCtx, BR, Base, Top, std::move(Report));
153-
#endif
154-
155172
return Report;
156173
}
157174
}
158175

159176
return nullptr;
160177
}
161178

162-
std::unique_ptr<BugReport> checkField(const FieldDecl *D, BugReporter &BR,
163-
const BugType &BT) {
164-
// TODO: other targets
165-
return checkFieldImpl<llvm::CompressedCapability::Cheri128>(D, BR, BT);
166-
}
179+
} // namespace
167180

168-
bool supportedTarget(const ASTContext &C) {
169-
const TargetInfo &TI = C.getTargetInfo();
170-
return TI.areAllPointersCapabilities() &&
171-
TI.getTriple().isAArch64(); // morello
172-
}
181+
SubObjectRepresentabilityChecker::CheckFieldFn
182+
SubObjectRepresentabilityChecker::getCheckFieldFn(ASTContext &ASTCtx) const {
183+
const TargetInfo &TI = ASTCtx.getTargetInfo();
184+
if (!TI.areAllPointersCapabilities())
185+
return nullptr;
173186

174-
} // namespace
187+
auto It = CheckFieldFnMap.find(TI.getTriple().getArch());
188+
if (It == CheckFieldFnMap.end())
189+
return nullptr;
190+
return It->second;
191+
}
175192

176193
void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
177194
AnalysisManager &mgr,
178195
BugReporter &BR) const {
179-
if (!supportedTarget(mgr.getASTContext()))
180-
return;
196+
CheckFieldFn checkField = getCheckFieldFn(mgr.getASTContext());
197+
if (!checkField)
198+
return; // skip this target
181199

182200
if (!R->isCompleteDefinition() || R->isDependentType())
183201
return;
184202

185203
if (!R->getLocation().isValid())
186204
return;
187205

188-
/*
189-
SrcMgr::CharacteristicKind Kind =
190-
BR.getSourceManager().getFileCharacteristic(Location);
191-
// Ignore records in system headers
192-
if (Kind != SrcMgr::C_User)
193-
return;
194-
*/
195-
196206
for (FieldDecl *D : R->fields()) {
197207
auto Report = checkField(D, BR, BT_1);
198208
if (Report)
@@ -203,8 +213,9 @@ void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
203213
void SubObjectRepresentabilityChecker::checkASTCodeBody(const Decl *D,
204214
AnalysisManager &mgr,
205215
BugReporter &BR) const {
206-
if (!supportedTarget(mgr.getASTContext()))
207-
return;
216+
CheckFieldFn checkField = getCheckFieldFn(mgr.getASTContext());
217+
if (!checkField)
218+
return; // skip this target
208219

209220
using namespace ast_matchers;
210221
auto Member = memberExpr().bind("member");
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %cheri_purecap_cc1 -analyze -verify %s \
2+
// RUN: -analyzer-checker=core,cheri.SubObjectRepresentability
3+
4+
struct R1 {
5+
struct {
6+
struct {
7+
char c;
8+
char a[0x9FF]; // no warn
9+
} f1good;
10+
struct {
11+
char c; // expected-note{{}}
12+
char a[0x1000]; // expected-warning{{Field 'a' of type 'char[4096]' (size 4096) requires 8 byte alignment for precise bounds; field offset is 1}}
13+
} f2bad;
14+
struct {
15+
int c[2];
16+
char a[0x1000]; // no warn
17+
} f3good __attribute__((aligned(8)));
18+
} s2;
19+
} s1;
20+
21+
struct S2 {
22+
int x[3];
23+
int *px;
24+
};
25+
26+
struct R2 {
27+
char x[0x50]; // expected-note{{16/80}}
28+
struct S2 s2; // expected-note{{32/32 bytes exposed (may expose capability!)}}
29+
char c; // expected-note{{1}}
30+
char a[0x8000]; // expected-warning{{Field 'a' of type 'char[32768]' (size 32768) requires 64 byte alignment for precise bounds; field offset is 113 (aligned to 1); Current bounds: 64-32896}}
31+
char y[32]; // expected-note{{15/32}}
32+
};

0 commit comments

Comments
 (0)