ddcc updated this revision to Diff 98545. ddcc added a comment. Rebase
https://reviews.llvm.org/D28953 Files: include/clang/StaticAnalyzer/Checkers/SValExplainer.h lib/StaticAnalyzer/Core/SValBuilder.cpp lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp test/Analysis/bitwise-ops.c test/Analysis/conditional-path-notes.c test/Analysis/explain-svals.cpp test/Analysis/std-c-library-functions.c
Index: test/Analysis/std-c-library-functions.c =================================================================== --- test/Analysis/std-c-library-functions.c +++ test/Analysis/std-c-library-functions.c @@ -57,8 +57,7 @@ size_t y = fread(buf, sizeof(int), 10, fp); clang_analyzer_eval(y <= 10); // expected-warning{{TRUE}} size_t z = fwrite(buf, sizeof(int), y, fp); - // FIXME: should be TRUE once symbol-symbol constraint support is improved. - clang_analyzer_eval(z <= y); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z <= y); // expected-warning{{TRUE}} } ssize_t getline(char **, size_t *, FILE *); Index: test/Analysis/explain-svals.cpp =================================================================== --- test/Analysis/explain-svals.cpp +++ test/Analysis/explain-svals.cpp @@ -69,7 +69,7 @@ static int stat; clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}} clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}} - clang_analyzer_explain(x + y); // expected-warning-re{{{{^unknown value$}}}} + clang_analyzer_explain(x + y); // expected-warning-re{{{{^\(argument 'x'\) \+ \(argument 'y'\)$}}}} clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}} clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}} clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}} Index: test/Analysis/conditional-path-notes.c =================================================================== --- test/Analysis/conditional-path-notes.c +++ test/Analysis/conditional-path-notes.c @@ -77,7 +77,8 @@ void testNonDiagnosableBranchArithmetic(int a, int b) { if (a - b) { - // expected-note@-1 {{Taking true branch}} + // expected-note@-1 {{Assuming the condition is true}} + // expected-note@-2 {{Taking true branch}} *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}} // expected-note@-1 {{Dereference of null pointer}} } @@ -1573,12 +1574,75 @@ // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>event</string> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>11</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>depth</key><integer>0</integer> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Assuming the condition is true</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Assuming the condition is true</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>kind</key><string>control</string> +// CHECK-NEXT: <key>edges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>start</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>79</integer> +// CHECK-NEXT: <key>col</key><integer>7</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>end</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1594,25 +1658,25 @@ // CHECK-NEXT: <key>start</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> // CHECK-NEXT: <key>end</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>24</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>24</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1624,20 +1688,20 @@ // CHECK-NEXT: <key>kind</key><string>event</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>24</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>ranges</key> // CHECK-NEXT: <array> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>5</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>26</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> @@ -1658,10 +1722,10 @@ // CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f56671e5f67c73abef619b56f7c29fa4</string> // CHECK-NEXT: <key>issue_context_kind</key><string>function</string> // CHECK-NEXT: <key>issue_context</key><string>testNonDiagnosableBranchArithmetic</string> -// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string> +// CHECK-NEXT: <key>issue_hash_function_offset</key><string>4</string> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> -// CHECK-NEXT: <key>line</key><integer>81</integer> +// CHECK-NEXT: <key>line</key><integer>82</integer> // CHECK-NEXT: <key>col</key><integer>24</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> Index: test/Analysis/bitwise-ops.c =================================================================== --- test/Analysis/bitwise-ops.c +++ test/Analysis/bitwise-ops.c @@ -7,10 +7,9 @@ // Sanity check CHECK(x); // expected-warning{{TRUE}} CHECK(x & 1); // expected-warning{{TRUE}} - - // False positives due to SValBuilder giving up on certain kinds of exprs. - CHECK(1 - x); // expected-warning{{UNKNOWN}} - CHECK(x & y); // expected-warning{{UNKNOWN}} + + CHECK(1 - x); // expected-warning{{TRUE}} + CHECK(x & y); // expected-warning{{TRUE}} } int testConstantShifts_PR18073(int which) { @@ -29,4 +28,4 @@ default: return 0; } -} \ No newline at end of file +} Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp =================================================================== --- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -671,12 +671,12 @@ // If one of the operands is a symbol and the other is a constant, // build an expression for use by the constraint manager. if (SymbolRef rSym = rhs.getAsLocSymbol()) { - // We can only build expressions with symbols on the left, - // so we need a reversible operator. + const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); + + // Prefer expressions with symbols on the left if (!BinaryOperator::isComparisonOp(op)) - return UnknownVal(); + return makeNonLoc(lVal, op, rSym, resultTy); - const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); op = BinaryOperator::reverseComparisonOp(op); return makeNonLoc(rSym, op, lVal, resultTy); } @@ -996,7 +996,10 @@ if (SymbolRef Sym = V.getAsSymbol()) return state->getConstraintManager().getSymVal(state, Sym); - // FIXME: Add support for SymExprs. + if (Optional<NonLoc> NV = V.getAs<NonLoc>()) + if (SymbolRef Sym = NV->getAsSymExpr()) + return state->getConstraintManager().getSymVal(state, Sym); + return nullptr; } Index: lib/StaticAnalyzer/Core/SValBuilder.cpp =================================================================== --- lib/StaticAnalyzer/Core/SValBuilder.cpp +++ lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -353,14 +353,11 @@ BinaryOperator::Opcode Op, NonLoc LHS, NonLoc RHS, QualType ResultTy) { - if (!State->isTainted(RHS) && !State->isTainted(LHS)) - return UnknownVal(); - const SymExpr *symLHS = LHS.getAsSymExpr(); const SymExpr *symRHS = RHS.getAsSymExpr(); // TODO: When the Max Complexity is reached, we should conjure a symbol // instead of generating an Unknown value and propagate the taint info to it. - const unsigned MaxComp = 10000; // 100000 28X + const unsigned MaxComp = 1000; // 10000 28X if (symLHS && symRHS && (symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp) Index: include/clang/StaticAnalyzer/Checkers/SValExplainer.h =================================================================== --- include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -125,17 +125,25 @@ return OS.str(); } - // TODO: IntSymExpr doesn't appear in practice. - // Add the relevant code once it does. + std::string VisitIntSymExpr(const IntSymExpr *S) { + std::string Str; + llvm::raw_string_ostream OS(Str); + OS << S->getLHS() + << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " " + << "(" << Visit(S->getRHS()) << ") "; + return OS.str(); + } std::string VisitSymSymExpr(const SymSymExpr *S) { return "(" + Visit(S->getLHS()) + ") " + std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) + " (" + Visit(S->getRHS()) + ")"; } - // TODO: SymbolCast doesn't appear in practice. - // Add the relevant code once it does. + std::string VisitSymbolCast(const SymbolCast *S) { + return "cast of type '" + S->getType().getAsString() + "' of " + + Visit(S->getOperand()); + } std::string VisitSymbolicRegion(const SymbolicRegion *R) { // Explain 'this' object here.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits