Skip to content

Commit 264aa7a

Browse files
eupharinaresistor
authored andcommitted
[CHERI_CSA] AllocationChecker: suppress for bounded suballocations
1 parent a0c0dc1 commit 264aa7a

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

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

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,20 @@ using EscapePair = std::pair<const MemRegion*, EscapeInfo>;
4444
namespace {
4545
class AllocationChecker : public Checker<check::PostStmt<CastExpr>,
4646
check::PreCall,
47+
check::PostCall,
4748
check::Bind,
4849
check::EndFunction> {
4950
BugType BT_Default{this, "Allocation partitioning", "CHERI portability"};
5051
BugType BT_KnownReg{this, "Heap or static allocation partitioning",
5152
"CHERI portability"};
5253

5354
const CallDescriptionSet IgnoreFnSet = {
54-
{{CDM::SimpleFunc, {"free"}, 1}},
55+
{CDM::SimpleFunc, {"free"}, 1},
56+
};
57+
58+
const CallDescriptionSet CheriBoundsFnSet = {
59+
{CDM::SimpleFunc, {"cheri_bounds_set"}, 2},
60+
{CDM::SimpleFunc, {"cheri_bounds_set_exact"}, 2},
5561
};
5662

5763

@@ -81,6 +87,7 @@ class AllocationChecker : public Checker<check::PostStmt<CastExpr>,
8187
public:
8288
void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
8389
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
90+
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
8491
void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
8592
void checkEndFunction(const ReturnStmt *RS, CheckerContext &Ctx) const;
8693

@@ -96,6 +103,8 @@ class AllocationChecker : public Checker<check::PostStmt<CastExpr>,
96103
REGISTER_MAP_WITH_PROGRAMSTATE(AllocMap, const MemRegion *, QualType)
97104
REGISTER_MAP_WITH_PROGRAMSTATE(ShiftMap, const MemRegion *, const MemRegion *)
98105
REGISTER_SET_WITH_PROGRAMSTATE(SuballocationSet, const MemRegion *)
106+
REGISTER_SET_WITH_PROGRAMSTATE(BoundedSet, const MemRegion *)
107+
99108

100109
namespace {
101110
std::pair<const MemRegion *, bool> getAllocationStart(const ASTContext &ASTCtx,
@@ -207,21 +216,25 @@ void AllocationChecker::checkPostStmt(const CastExpr *CE,
207216
const MemRegion *MR = SrcVal.getAsRegion();
208217
if (!MR)
209218
return;
210-
const MemSpaceRegion *MemSpace = MR->getMemorySpace();
211-
if (!isa<HeapSpaceRegion, GlobalsSpaceRegion, StackSpaceRegion>(MemSpace))
219+
220+
ProgramStateRef State = C.getState();
221+
if (State->contains<BoundedSet>(MR))
212222
return;
213223

214224
const ASTContext &ASTCtx = C.getASTContext();
215-
ProgramStateRef State = C.getState();
216225
bool Updated = false;
217-
218226
std::pair<const MemRegion *, bool> StartPair =
219227
getAllocationStart(ASTCtx, MR, State);
228+
220229
const MemRegion *SR = StartPair.first;
221230
if (!isAllocation(SR))
222231
return;
223232
bool ZeroShift = StartPair.second;
224233

234+
const MemSpaceRegion *MemSpace = SR->getMemorySpace();
235+
if (!isa<HeapSpaceRegion, GlobalsSpaceRegion, StackSpaceRegion>(MemSpace))
236+
return;
237+
225238
SVal DstVal = C.getSVal(CE);
226239
const MemRegion *DMR = DstVal.getAsRegion();
227240
if (MR->getAs<ElementRegion>() && (!DMR || !DMR->getAs<ElementRegion>())) {
@@ -267,9 +280,9 @@ void AllocationChecker::checkPostStmt(const CastExpr *CE,
267280

268281
void AllocationChecker::checkPreCall(const CallEvent &Call,
269282
CheckerContext &C) const {
270-
if (IgnoreFnSet.contains(Call))
283+
if (IgnoreFnSet.contains(Call) || CheriBoundsFnSet.contains(Call))
271284
return;
272-
285+
273286
ProgramStateRef State = C.getState();
274287
ExplodedNode *N = nullptr;
275288
bool Updated = false;
@@ -305,6 +318,25 @@ void AllocationChecker::checkPreCall(const CallEvent &Call,
305318
C.addTransition(State, N ? N : C.getPredecessor());
306319
}
307320

321+
void AllocationChecker::checkPostCall(const CallEvent &Call,
322+
CheckerContext &C) const {
323+
if (!CheriBoundsFnSet.contains(Call))
324+
return;
325+
const MemRegion *MR = C.getSVal(Call.getArgExpr(0)).getAsRegion();
326+
const MemRegion *ResMR = C.getSVal(Call.getOriginExpr()).getAsRegion();
327+
if (!MR || !ResMR)
328+
return;
329+
330+
ProgramStateRef State = C.getState();
331+
if (!State->contains<SuballocationSet>(MR) ||
332+
!State->contains<SuballocationSet>(ResMR))
333+
return;
334+
335+
State = State->remove<SuballocationSet>(ResMR);
336+
State = State->add<BoundedSet>(ResMR);
337+
C.addTransition(State);
338+
}
339+
308340
void AllocationChecker::checkBind(SVal L, SVal V, const Stmt *S,
309341
CheckerContext &C) const {
310342
const MemRegion *Dst = L.getAsRegion();

clang/test/Analysis/Checkers/CHERI/allocation.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %cheri_purecap_cc1 -analyze -verify %s \
2-
// RUN: -analyzer-checker=core,unix,alpha.cheri.Allocation
2+
// RUN: -analyzer-checker=core,unix,alpha.cheri.Allocation,cheri.CheriAPIModelling
33

44
typedef __typeof__(sizeof(int)) size_t;
55
extern void * malloc(size_t);
@@ -81,3 +81,11 @@ void test_6(int n1, int n2) {
8181
struct S2 **p2 = (struct S2 **)(p1+n1);
8282
foo(p2); // no warn
8383
}
84+
85+
void *cheri_bounds_set(void *c, size_t x);
86+
void test_7(int n1, int n2) {
87+
struct S1 *p1 = malloc(sizeof(struct S1)*n1 + sizeof(struct S2)*n2);
88+
struct S2 *p2 = (struct S2 *)(p1+n1);
89+
struct S2 *p3 = cheri_bounds_set(p2, sizeof(struct S2)*n2);
90+
foo(p3); // no-warn
91+
}

0 commit comments

Comments
 (0)