Skip to content

Commit 336eb74

Browse files
[analyzer] Handle [[assume(cond)]] as __builtin_assume(cond)
Resolves #100762
1 parent 70b9440 commit 336eb74

File tree

5 files changed

+106
-1
lines changed

5 files changed

+106
-1
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

+4
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ class ExprEngine {
498498
void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
499499
ExplodedNodeSet &Dst);
500500

501+
/// VisitAttributedStmt - Transfer function logic for AttributedStmt
502+
void VisitAttributedStmt(const AttributedStmt *A, ExplodedNode *Pred,
503+
ExplodedNodeSet &Dst);
504+
501505
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
502506
void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
503507
ExplodedNodeSet &Dst);

clang/lib/Analysis/CFG.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,45 @@ reverse_children::reverse_children(Stmt *S) {
456456
IE->getNumInits());
457457
return;
458458
}
459+
case Stmt::AttributedStmtClass: {
460+
AttributedStmt *attrStmt = cast<AttributedStmt>(S);
461+
assert(attrStmt);
462+
463+
{
464+
// for an attributed stmt, the "children()" returns only the NullStmt
465+
// (;) but semantically the "children" are supposed to be the
466+
// expressions _within_ i.e. the two square brackets i.e. [[ HERE ]]
467+
// so we add the subexpressions first, _then_ add the "children"
468+
469+
for (auto *child : attrStmt->children()) {
470+
llvm::errs() << "\nchildren=";
471+
child->dump();
472+
}
473+
474+
for (const Attr *attr : attrStmt->getAttrs()) {
475+
{
476+
llvm::errs() << "\nattr=";
477+
attr->printPretty(llvm::errs(), PrintingPolicy{LangOptions{}});
478+
}
479+
480+
// i.e. one `assume()`
481+
CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
482+
if (!assumeAttr) {
483+
continue;
484+
}
485+
// Only handles [[ assume(<assumption>) ]] right now
486+
Expr *assumption = assumeAttr->getAssumption();
487+
childrenBuf.push_back(assumption);
488+
}
489+
490+
// children() for an AttributedStmt is NullStmt(;)
491+
llvm::append_range(childrenBuf, attrStmt->children());
492+
493+
// This needs to be done *after* childrenBuf has been populated.
494+
children = childrenBuf;
495+
}
496+
return;
497+
}
459498
default:
460499
break;
461500
}
@@ -2475,6 +2514,14 @@ static bool isFallthroughStatement(const AttributedStmt *A) {
24752514
return isFallthrough;
24762515
}
24772516

2517+
static bool isCXXAssumeAttr(const AttributedStmt *A) {
2518+
bool hasAssumeAttr = hasSpecificAttr<CXXAssumeAttr>(A->getAttrs());
2519+
2520+
assert((!hasAssumeAttr || isa<NullStmt>(A->getSubStmt())) &&
2521+
"expected [[assume]] not to have children");
2522+
return hasAssumeAttr;
2523+
}
2524+
24782525
CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
24792526
AddStmtChoice asc) {
24802527
// AttributedStmts for [[likely]] can have arbitrary statements as children,
@@ -2490,6 +2537,11 @@ CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
24902537
appendStmt(Block, A);
24912538
}
24922539

2540+
if (isCXXAssumeAttr(A) && asc.alwaysAdd(*this, A)) {
2541+
autoCreateBlock();
2542+
appendStmt(Block, A);
2543+
}
2544+
24932545
return VisitChildren(A);
24942546
}
24952547

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -1946,7 +1946,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
19461946
// to be explicitly evaluated.
19471947
case Stmt::PredefinedExprClass:
19481948
case Stmt::AddrLabelExprClass:
1949-
case Stmt::AttributedStmtClass:
19501949
case Stmt::IntegerLiteralClass:
19511950
case Stmt::FixedPointLiteralClass:
19521951
case Stmt::CharacterLiteralClass:
@@ -1977,6 +1976,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
19771976
break;
19781977
}
19791978

1979+
case Stmt::AttributedStmtClass: {
1980+
Bldr.takeNodes(Pred);
1981+
VisitAttributedStmt(cast<AttributedStmt>(S), Pred, Dst);
1982+
Bldr.addNodes(Dst);
1983+
break;
1984+
}
1985+
19801986
case Stmt::CXXDefaultArgExprClass:
19811987
case Stmt::CXXDefaultInitExprClass: {
19821988
Bldr.takeNodes(Pred);

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -1200,3 +1200,30 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
12001200
// FIXME: Move all post/pre visits to ::Visit().
12011201
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
12021202
}
1203+
1204+
void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
1205+
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1206+
1207+
ExplodedNodeSet CheckerPreStmt;
1208+
getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
1209+
1210+
ExplodedNodeSet EvalSet;
1211+
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
1212+
1213+
{
1214+
for (const auto *attr : A->getAttrs()) {
1215+
1216+
CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
1217+
if (!assumeAttr) {
1218+
continue;
1219+
}
1220+
Expr *AssumeExpr = assumeAttr->getAssumption();
1221+
1222+
for (auto *node : CheckerPreStmt) {
1223+
Visit(AssumeExpr, node, EvalSet);
1224+
}
1225+
}
1226+
}
1227+
1228+
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
1229+
}

clang/test/Analysis/out-of-bounds-new.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,19 @@ int test_reference_that_might_be_after_the_end(int idx) {
180180
return ref;
181181
}
182182

183+
// From: https://github.com/llvm/llvm-project/issues/100762
184+
extern int arr[10];
185+
void using_builtin(int x) {
186+
__builtin_assume(x > 101); // CallExpr
187+
arr[x] = 404; // expected-warning{{Out of bound access to memory}}
188+
}
189+
190+
void using_assume_attr(int ax) {
191+
[[assume(ax > 100)]]; // NullStmt with an attribute
192+
arr[ax] = 405; // expected-warning{{Out of bound access to memory}}
193+
}
194+
195+
void using_many_assume_attr(int yx) {
196+
[[assume(yx > 104), assume(yx > 200), assume(yx < 300)]]; // NullStmt with an attribute
197+
arr[yx] = 406; // expected-warning{{Out of bound access to memory}}
198+
}

0 commit comments

Comments
 (0)