Skip to content

Commit c288bdc

Browse files
Ignore assumptions with side-effects
1 parent d55851b commit c288bdc

File tree

3 files changed

+86
-17
lines changed

3 files changed

+86
-17
lines changed

clang/lib/Analysis/CFG.cpp

+34-11
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,10 @@ namespace {
431431
class reverse_children {
432432
llvm::SmallVector<Stmt *, 12> childrenBuf;
433433
ArrayRef<Stmt *> children;
434+
ASTContext *astContext;
434435

435436
public:
436-
reverse_children(Stmt *S);
437+
reverse_children(Stmt *S, ASTContext *astContext = nullptr);
437438

438439
using iterator = ArrayRef<Stmt *>::reverse_iterator;
439440

@@ -443,7 +444,8 @@ class reverse_children {
443444

444445
} // namespace
445446

446-
reverse_children::reverse_children(Stmt *S) {
447+
reverse_children::reverse_children(Stmt *S, ASTContext *AstC)
448+
: astContext(AstC) {
447449
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
448450
children = CE->getRawSubExprs();
449451
return;
@@ -457,16 +459,37 @@ reverse_children::reverse_children(Stmt *S) {
457459
return;
458460
}
459461
case Stmt::AttributedStmtClass: {
460-
auto Attrs = cast<AttributedStmt>(S)->getAttrs();
462+
assert(S->getStmtClass() == Stmt::AttributedStmtClass);
463+
assert(this->astContext &&
464+
"Attributes need the ast context to determine side-effects");
465+
AttributedStmt *AS = cast<AttributedStmt>(S);
466+
assert(attrStmt);
467+
468+
// for an attributed stmt, the "children()" returns only the NullStmt
469+
// (;) but semantically the "children" are supposed to be the
470+
// expressions _within_ i.e. the two square brackets i.e. [[ HERE ]]
471+
// so we add the subexpressions first, _then_ add the "children"
472+
for (const Attr *Attr : AS->getAttrs()) {
473+
// Only handles [[ assume(<assumption>) ]] right now
474+
CXXAssumeAttr const *AssumeAttr = llvm::dyn_cast<CXXAssumeAttr>(Attr);
475+
if (!AssumeAttr) {
476+
continue;
477+
}
478+
Expr *AssumeExpr = AssumeAttr->getAssumption();
479+
// If we skip adding the assumption expression to CFG,
480+
// it doesn't get "branch"-ed by symbol analysis engine
481+
// presumably because it's literally not in the CFG
461482

462-
// We only handle `[[assume(...)]]` attributes for now.
463-
if (const auto *A = getSpecificAttr<CXXAssumeAttr>(Attrs)) {
464-
childrenBuf.push_back(A->getAssumption());
465-
llvm::append_range(childrenBuf, S->children());
466-
children = childrenBuf;
467-
return;
483+
if (AssumeExpr->HasSideEffects(*astContext)) {
484+
continue;
485+
}
486+
childrenBuf.push_back(AssumeExpr);
468487
}
469-
break;
488+
// children() for an CXXAssumeAttr is NullStmt(;)
489+
// for others, it will have existing behavior
490+
llvm::append_range(childrenBuf, AS->children());
491+
children = childrenBuf;
492+
return;
470493
}
471494
default:
472495
break;
@@ -2436,7 +2459,7 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
24362459

24372460
// Visit the children in their reverse order so that they appear in
24382461
// left-to-right (natural) order in the CFG.
2439-
reverse_children RChildren(S);
2462+
reverse_children RChildren(S, Context);
24402463
for (Stmt *Child : RChildren) {
24412464
if (Child)
24422465
if (CFGBlock *R = Visit(Child))

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,23 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "clang/AST/ASTContext.h"
1314
#include "clang/AST/DeclCXX.h"
1415
#include "clang/AST/ParentMap.h"
1516
#include "clang/AST/StmtCXX.h"
17+
#include "clang/Analysis/AnalysisDeclContext.h"
1618
#include "clang/Analysis/ConstructionContext.h"
19+
#include "clang/Analysis/ProgramPoint.h"
1720
#include "clang/Basic/PrettyStackTrace.h"
1821
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
1922
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
2023
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
24+
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
2125
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
26+
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
27+
#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
2228
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
29+
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
2330
#include "llvm/ADT/STLExtras.h"
2431
#include "llvm/ADT/Sequence.h"
2532
#include <optional>
@@ -1209,9 +1216,14 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
12091216
ExplodedNodeSet EvalSet;
12101217
StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx);
12111218

1212-
if (const auto *AssumeAttr = getSpecificAttr<CXXAssumeAttr>(A->getAttrs())) {
1219+
for (const auto *attr : A->getAttrs()) {
1220+
CXXAssumeAttr const *AssumeAttr = llvm::dyn_cast<CXXAssumeAttr>(attr);
1221+
if (!AssumeAttr) {
1222+
continue;
1223+
}
1224+
Expr *AssumeExpr = AssumeAttr->getAssumption();
12131225
for (ExplodedNode *N : CheckerPreStmt) {
1214-
Visit(AssumeAttr->getAssumption(), N, EvalSet);
1226+
Visit(AssumeExpr, N, EvalSet);
12151227
}
12161228
}
12171229

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

+38-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
template <typename T> void clang_analyzer_dump(T);
55
template <typename T> void clang_analyzer_value(T);
66
void clang_analyzer_eval(bool);
7+
template <typename T>
8+
void clang_analyzer_explain(T);
79

810
// Tests doing an out-of-bounds access after the end of an array using:
911
// - constant integer index
@@ -189,22 +191,54 @@ int test_reference_that_might_be_after_the_end(int idx) {
189191
extern int arrOf10[10];
190192
void using_builtin(int x) {
191193
__builtin_assume(x > 101); // CallExpr
192-
arrOf10[x] = 404; // expected-warning{{Out of bound access to memory}}
194+
arrOf10[x] = 404; // expected-warning {{Out of bound access to memory}}
193195
}
194196

195197
void using_assume_attr(int ax) {
196198
[[assume(ax > 100)]]; // NullStmt with an "assume" attribute.
197-
arrOf10[ax] = 405; // expected-warning{{Out of bound access to memory}}
199+
arrOf10[ax] = 405; // expected-warning {{Out of bound access to memory}}
198200
}
199201

200202
void using_many_assume_attr(int yx) {
201203
[[assume(yx > 104), assume(yx > 200), assume(yx < 300)]]; // NullStmt with an attribute
202-
arrOf10[yx] = 406; // expected-warning{{Out of bounsssd access to memory}}
204+
arrOf10[yx] = 406; // expected-warning{{Out of bound access to memory}}
203205
}
204206

207+
208+
int using_builtin_assume_has_no_sideeffects(int y) {
209+
// We should not apply sideeffects of the argument of [[assume(...)]].
210+
// "y" should not get incremented;
211+
__builtin_assume(++y == 43); // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
212+
clang_analyzer_eval(y == 42); // expected-warning {{FALSE}}
213+
return y;
214+
}
215+
216+
217+
205218
int using_assume_attr_has_no_sideeffects(int y) {
219+
206220
// We should not apply sideeffects of the argument of [[assume(...)]].
207-
[[assume(++y == 43)]]; // "y" should not get incremented
221+
// "y" should not get incremented;
222+
[[assume(++y == 43)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
223+
208224
clang_analyzer_eval(y == 42); // expected-warning {{TRUE}} expected-warning {{FALSE}} FIXME: This should be only TRUE.
225+
226+
clang_analyzer_eval(y == 43); // expected-warning {{FALSE}} expected-warning {{TRUE}} FIXME: This should be only FALSE.
227+
209228
return y;
210229
}
230+
231+
232+
int using_builtinassume_has_no_sideeffects(int u) {
233+
// We should not apply sideeffects of the argument of __builtin_assume(...)
234+
// "u" should not get incremented;
235+
__builtin_assume(++u == 43); // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
236+
237+
// FIXME: evaluate this to true
238+
clang_analyzer_eval(u == 42); // expected-warning {{FALSE}} current behavior
239+
240+
// FIXME: evaluate this to false
241+
clang_analyzer_eval(u == 43); // expected-warning {{TRUE}} current behavior
242+
243+
return u;
244+
}

0 commit comments

Comments
 (0)