Skip to content

Commit 11ff3c0

Browse files
eupharinaresistor
authored andcommitted
[CHERI_CSA] SubObjectRepresentability: support other CHERI targets
1 parent 886885e commit 11ff3c0

File tree

2 files changed

+80
-39
lines changed

2 files changed

+80
-39
lines changed

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

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ 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,
36+
BugReporter &BR,
37+
const BugType &BT);
38+
3339
class SubObjectRepresentabilityChecker
3440
: public Checker<check::ASTDecl<RecordDecl>, check::ASTCodeBody> {
3541
BugType BT_1{this, "Field with imprecise subobject bounds",
@@ -42,6 +48,21 @@ class SubObjectRepresentabilityChecker
4248
BugReporter &BR) const;
4349
void checkASTCodeBody(const Decl *D, AnalysisManager &mgr,
4450
BugReporter &BR) const;
51+
52+
private:
53+
54+
using CheckFieldFn = std::function<std::unique_ptr<BugReport>(
55+
const FieldDecl *D, BugReporter &BR, const BugType &BT)>;
56+
57+
const std::map<llvm::Triple::ArchType, CheckFieldFn> CheckFieldFnMap = {
58+
//{llvm::Triple::aarch64, &checkFieldImpl<CompressedCap128m>},
59+
{llvm::Triple::mips, &checkFieldImpl<llvm::CompressedCapability::Cheri64>},
60+
{llvm::Triple::mips64, &checkFieldImpl<llvm::CompressedCapability::Cheri128>},
61+
{llvm::Triple::riscv32, &checkFieldImpl<llvm::CompressedCapability::Cheri64>},
62+
{llvm::Triple::riscv64, &checkFieldImpl<llvm::CompressedCapability::Cheri128>}
63+
};
64+
65+
CheckFieldFn getCheckFieldFn(ASTContext &ASTCtx) const;
4566
};
4667

4768
} //namespace
@@ -116,8 +137,8 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D,
116137
uint64_t Offset = ASTCtx.getFieldOffset(D) / 8;
117138
if (Offset > 0) {
118139
uint64_t Size = ASTCtx.getTypeSize(T) / 8;
119-
uint64_t ReqAlign = llvm::CompressedCapability::GetRequiredAlignment(
120-
Size, llvm::CompressedCapability::Cheri128).value();
140+
uint64_t ReqAlign =
141+
llvm::CompressedCapability::GetRequiredAlignment(Size, Handler).value();
121142
uint64_t CurAlign = 1 << llvm::countr_zero(Offset);
122143
if (CurAlign < ReqAlign) {
123144
/* Emit warning */
@@ -132,15 +153,14 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D,
132153
OS << " field offset is " << Offset;
133154
OS << " (aligned to " << CurAlign << ");";
134155

135-
#if 0
136-
const RecordDecl *Parent = D->getParent();
137-
uint64_t ParentSize = ASTCtx.getTypeSize(Parent->getTypeForDecl()) / 8;
138-
typename Handler::cap_t MockCap =
139-
getBoundedCap<Handler>(ParentSize, Offset, Size);
140-
uint64_t Base = MockCap.base();
141-
uint64_t Top = MockCap.top();
156+
uint64_t OffsetToAlign = Offset % ReqAlign;
157+
uint64_t Base = Offset - OffsetToAlign;
158+
uint64_t AlignedSize = Size + OffsetToAlign;
159+
uint64_t TailPadding = static_cast<uint64_t>(
160+
llvm::CompressedCapability::GetRequiredTailPadding(AlignedSize,
161+
Handler));
162+
uint64_t Top = Base + AlignedSize + TailPadding;
142163
OS << " Current bounds: " << Base << "-" << Top;
143-
#endif
144164

145165
// Note that this will fire for every translation unit that uses this
146166
// class. This is suboptimal, but at least scan-build will merge
@@ -151,53 +171,41 @@ std::unique_ptr<BugReport> checkFieldImpl(const FieldDecl *D,
151171
Report->setDeclWithIssue(D);
152172
Report->addRange(D->getSourceRange());
153173

154-
#if 0
155174
Report = reportExposedFields(D, ASTCtx, BR, Base, Top, std::move(Report));
156-
#endif
157-
158175
return Report;
159176
}
160177
}
161178

162179
return nullptr;
163180
}
164181

165-
std::unique_ptr<BugReport> checkField(const FieldDecl *D,
166-
BugReporter &BR,
167-
const BugType &BT) {
168-
// TODO: other targets
169-
return checkFieldImpl<llvm::CompressedCapability::Cheri128>(D, BR, BT);
170-
}
171-
172-
bool supportedTarget(const ASTContext &C) {
173-
const TargetInfo &TI = C.getTargetInfo();
174-
return TI.areAllPointersCapabilities()
175-
&& TI.getTriple().isAArch64(); // morello
176-
}
177-
178182
} // namespace
179183

184+
SubObjectRepresentabilityChecker::CheckFieldFn
185+
SubObjectRepresentabilityChecker::getCheckFieldFn(ASTContext &ASTCtx) const {
186+
const TargetInfo &TI = ASTCtx.getTargetInfo();
187+
if (!TI.areAllPointersCapabilities())
188+
return nullptr;
189+
190+
auto It = CheckFieldFnMap.find(TI.getTriple().getArch());
191+
if (It == CheckFieldFnMap.end())
192+
return nullptr;
193+
return It->second;
194+
}
180195

181196
void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
182197
AnalysisManager &mgr,
183198
BugReporter &BR) const {
184-
if (!supportedTarget(mgr.getASTContext()))
185-
return;
199+
CheckFieldFn checkField = getCheckFieldFn(mgr.getASTContext());
200+
if (!checkField)
201+
return; // skip this target
186202

187203
if (!R->isCompleteDefinition() || R->isDependentType())
188204
return;
189205

190206
if (!R->getLocation().isValid())
191207
return;
192-
193-
/*
194-
SrcMgr::CharacteristicKind Kind =
195-
BR.getSourceManager().getFileCharacteristic(Location);
196-
// Ignore records in system headers
197-
if (Kind != SrcMgr::C_User)
198-
return;
199-
*/
200-
208+
201209
for (FieldDecl *D : R->fields()) {
202210
auto Report = checkField(D, BR, BT_1);
203211
if (Report)
@@ -208,8 +216,9 @@ void SubObjectRepresentabilityChecker::checkASTDecl(const RecordDecl *R,
208216
void SubObjectRepresentabilityChecker::checkASTCodeBody(const Decl *D,
209217
AnalysisManager &mgr,
210218
BugReporter &BR) const {
211-
if (!supportedTarget(mgr.getASTContext()))
212-
return;
219+
CheckFieldFn checkField = getCheckFieldFn(mgr.getASTContext());
220+
if (!checkField)
221+
return; // skip this target
213222

214223
using namespace ast_matchers;
215224
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)