From: Jordan Rose Date: Wed, 13 Feb 2013 03:11:06 +0000 (+0000) Subject: [analyzer] Use Clang's evaluation for global constants and default arguments. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=42b130b20a46d49b3d8bfb56d4bbc9624f0cd8e0;p=platform%2Fupstream%2Fllvm.git [analyzer] Use Clang's evaluation for global constants and default arguments. Previously, we were handling only simple integer constants for globals and the smattering of implicitly-valued expressions handled by Environment for default arguments. Now, we can use any integer constant expression that Clang can evaluate, in addition to everything we handled before. PR15094 / llvm-svn: 175026 --- diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index b6c44bf..2b069a0 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -37,9 +37,6 @@ static const Expr *ignoreTransparentExprs(const Expr *E) { case Stmt::SubstNonTypeTemplateParmExprClass: E = cast(E)->getReplacement(); break; - case Stmt::CXXDefaultArgExprClass: - E = cast(E)->getExpr(); - break; default: // This is the base case: we can't look through more than we already have. return E; @@ -75,7 +72,6 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, switch (S->getStmtClass()) { case Stmt::CXXBindTemporaryExprClass: - case Stmt::CXXDefaultArgExprClass: case Stmt::ExprWithCleanupsClass: case Stmt::GenericSelectionExprClass: case Stmt::OpaqueValueExprClass: diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index f092f1a..18ac096 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -639,7 +639,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::StringLiteralClass: case Stmt::ObjCStringLiteralClass: case Stmt::CXXBindTemporaryExprClass: - case Stmt::CXXDefaultArgExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: { Bldr.takeNodes(Pred); @@ -650,6 +649,39 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, break; } + case Stmt::CXXDefaultArgExprClass: { + Bldr.takeNodes(Pred); + ExplodedNodeSet PreVisit; + getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); + + ExplodedNodeSet Tmp; + StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx); + + const LocationContext *LCtx = Pred->getLocationContext(); + const Expr *ArgE = cast(S)->getExpr(); + + // Avoid creating and destroying a lot of APSInts. + SVal V; + llvm::APSInt Result; + + for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end(); + I != E; ++I) { + ProgramStateRef State = (*I)->getState(); + + if (ArgE->EvaluateAsInt(Result, getContext())) + V = svalBuilder.makeIntVal(Result); + else + V = State->getSVal(ArgE, LCtx); + + State = State->BindExpr(S, LCtx, V); + Bldr2.generateNode(S, *I, State); + } + + getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); + Bldr.addNodes(Dst); + break; + } + case Expr::ObjCArrayLiteralClass: case Expr::ObjCDictionaryLiteralClass: // FIXME: explicitly model with a region and the actual contents diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 399f9eba..9572f64 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1524,11 +1524,14 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, QualType CT = Ctx.getCanonicalType(T); if (CT.isConstQualified()) { if (const Expr *Init = VD->getInit()) { - if (const IntegerLiteral *IL = - dyn_cast(Init->IgnoreParenCasts())) { - const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL); - return svalBuilder.evalCast(V, Init->getType(), IL->getType()); - } + llvm::APSInt Result; + if (Init->EvaluateAsInt(Result, Ctx)) + return svalBuilder.makeIntVal(Result); + + if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) + return svalBuilder.makeNull(); + + // FIXME: Handle other possible constant expressions. } } diff --git a/clang/test/Analysis/global-region-invalidation.c b/clang/test/Analysis/global-region-invalidation.c index 113e6ae..77de9dd 100644 --- a/clang/test/Analysis/global-region-invalidation.c +++ b/clang/test/Analysis/global-region-invalidation.c @@ -67,15 +67,29 @@ int constIntGlob() { return 3 / *m; // expected-warning {{Division by zero}} } -extern const int x; +extern const int y; int constIntGlobExtern() { - if (x == 0) { + if (y == 0) { foo(); - return 5 / x; // expected-warning {{Division by zero}} + return 5 / y; // expected-warning {{Division by zero}} } return 0; } +static void * const ptr = 0; +void constPtrGlob() { + clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}} + foo(); + clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}} +} + +static const int x2 = x; +void constIntGlob2() { + clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}} + foo(); + clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}} +} + void testAnalyzerEvalIsPure() { extern int someGlobal; if (someGlobal == 0) { diff --git a/clang/test/Analysis/inline.cpp b/clang/test/Analysis/inline.cpp index 873b046..f0e69dd 100644 --- a/clang/test/Analysis/inline.cpp +++ b/clang/test/Analysis/inline.cpp @@ -216,7 +216,7 @@ namespace DefaultArgs { class Secret { public: - static const int value = 42; + static const int value = 40 + 2; int get(int i = value) { return i; } @@ -225,16 +225,40 @@ namespace DefaultArgs { void testMethod() { Secret obj; clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}} + clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} + } - // FIXME: Should be 'TRUE'. See PR13673 or . - clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} + enum ABC { + A = 0, + B = 1, + C = 2 + }; - // FIXME: Even if we constrain the variable, we still have a problem. - // See PR13385 or . - if (Secret::value != 42) - return; - clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} - clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} + int enumUser(ABC input = B) { + return static_cast(input); + } + + void testEnum() { + clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}} + } + + + int exprUser(int input = 2 * 4) { + return input; + } + + int complicatedExprUser(int input = 2 * Secret::value) { + return input; + } + + void testExprs() { + clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}} + + clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}} } }