Skip to content

Commit

Permalink
[analyzer] Handle [[assume(cond)]] as __builtin_assume(cond)
Browse files Browse the repository at this point in the history
Resolves #100762
  • Loading branch information
vinay-deshmukh committed Nov 16, 2024
1 parent 70b9440 commit daddb9e
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,10 @@ class ExprEngine {
void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// VisitAttributedStmt - Transfer function logic for AttributedStmt
void VisitAttributedStmt(const AttributedStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// VisitLogicalExpr - Transfer function logic for '&&', '||'
void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,36 @@ reverse_children::reverse_children(Stmt *S) {
IE->getNumInits());
return;
}
case Stmt::AttributedStmtClass: {
AttributedStmt *attrStmt = cast<AttributedStmt>(S);
assert(attrStmt);

{
// for an attributed stmt, the "children()" returns only the NullStmt
// (;) but semantically the "children" are supposed to be the
// expressions _within_ i.e. the two square brackets i.e. [[ HERE ]]
// so we add the subexpressions first, _then_ add the "children"

for (const Attr *attr : attrStmt->getAttrs()) {

// i.e. one `assume()`
CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
if (!assumeAttr) {
continue;
}
// Only handles [[ assume(<assumption>) ]] right now
Expr *assumption = assumeAttr->getAssumption();
childrenBuf.push_back(assumption);
}

// children() for an AttributedStmt is NullStmt(;)
llvm::append_range(childrenBuf, attrStmt->children());

// This needs to be done *after* childrenBuf has been populated.
children = childrenBuf;
}
return;
}
default:
break;
}
Expand Down Expand Up @@ -2475,6 +2505,14 @@ static bool isFallthroughStatement(const AttributedStmt *A) {
return isFallthrough;
}

static bool isCXXAssumeAttr(const AttributedStmt *A) {
bool hasAssumeAttr = hasSpecificAttr<CXXAssumeAttr>(A->getAttrs());

assert((!hasAssumeAttr || isa<NullStmt>(A->getSubStmt())) &&
"expected [[assume]] not to have children");
return hasAssumeAttr;
}

CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
AddStmtChoice asc) {
// AttributedStmts for [[likely]] can have arbitrary statements as children,
Expand All @@ -2490,6 +2528,11 @@ CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
appendStmt(Block, A);
}

if (isCXXAssumeAttr(A) && asc.alwaysAdd(*this, A)) {
autoCreateBlock();
appendStmt(Block, A);
}

return VisitChildren(A);
}

Expand Down
8 changes: 7 additions & 1 deletion clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1946,7 +1946,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// to be explicitly evaluated.
case Stmt::PredefinedExprClass:
case Stmt::AddrLabelExprClass:
case Stmt::AttributedStmtClass:
case Stmt::IntegerLiteralClass:
case Stmt::FixedPointLiteralClass:
case Stmt::CharacterLiteralClass:
Expand Down Expand Up @@ -1977,6 +1976,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}

case Stmt::AttributedStmtClass: {
Bldr.takeNodes(Pred);
VisitAttributedStmt(cast<AttributedStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}

case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass: {
Bldr.takeNodes(Pred);
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1200,3 +1200,30 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
}

void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {

ExplodedNodeSet CheckerPreStmt;
getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);

ExplodedNodeSet EvalSet;
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);

{
for (const auto *attr : A->getAttrs()) {

CXXAssumeAttr const *assumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
if (!assumeAttr) {
continue;
}
Expr *AssumeExpr = assumeAttr->getAssumption();

for (auto *node : CheckerPreStmt) {
Visit(AssumeExpr, node, EvalSet);
}
}
}

getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
}
16 changes: 16 additions & 0 deletions clang/test/Analysis/out-of-bounds-new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,19 @@ int test_reference_that_might_be_after_the_end(int idx) {
return ref;
}

// From: https://github.com/llvm/llvm-project/issues/100762
extern int arr[10];
void using_builtin(int x) {
__builtin_assume(x > 101); // CallExpr
arr[x] = 404; // expected-warning{{Out of bound access to memory}}
}

void using_assume_attr(int ax) {
[[assume(ax > 100)]]; // NullStmt with an attribute
arr[ax] = 405; // expected-warning{{Out of bound access to memory}}
}

void using_many_assume_attr(int yx) {
[[assume(yx > 104), assume(yx > 200), assume(yx < 300)]]; // NullStmt with an attribute
arr[yx] = 406; // expected-warning{{Out of bound access to memory}}
}

0 comments on commit daddb9e

Please sign in to comment.