martong created this revision. martong added reviewers: vsavchenko, NoQ, steakhal. Herald added subscribers: ASDenysPetrov, gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun, whisperity. Herald added a reviewer: Szelethus. martong requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Update `setConstraint` to simplify existing constraints (and adding the simplified constraint) when a new constraint is added. In this patch we just simply iterate over all existing constraints and try to simplfy them with simplifySVal. This solves the simplest problematic cases where we have two symbols in the tree, e.g.: int test_rhs_further_constrained(int x, int y) { if (x + y != 0) return 0; if (y != 0) return 0; clang_analyzer_eval(x + y == 0); // expected-warning{{TRUE}} clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} return 0; } This patch is the first step of a sequence of patches, and not intended to be commited as a standalone change. The sequence of patches (and the plan) is described here: https://reviews.llvm.org/D102696#2784624 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D103314 Files: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp clang/test/Analysis/find-binop-constraints.cpp
Index: clang/test/Analysis/find-binop-constraints.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/find-binop-constraints.cpp @@ -0,0 +1,115 @@ +// RUN: %clang_analyze_cc1 %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=debug.ExprInspection \ +// RUN: -analyzer-config eagerly-assume=false \ +// RUN: -verify + +void clang_analyzer_eval(bool); + +int test_legacy_behavior(int x, int y) { + if (y != 0) + return 0; + if (x + y != 0) + return 0; + clang_analyzer_eval(x + y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} + return y / (x + y); // expected-warning{{Division by zero}} +} + +int test_rhs_further_constrained(int x, int y) { + if (x + y != 0) + return 0; + if (y != 0) + return 0; + clang_analyzer_eval(x + y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} + return 0; +} + +int test_lhs_further_constrained(int x, int y) { + if (x + y != 0) + return 0; + if (x != 0) + return 0; + clang_analyzer_eval(x + y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} + return 0; +} + +int test_lhs_and_rhs_further_constrained(int x, int y) { + if (x % y != 1) + return 0; + if (x != 1) + return 0; + if (y != 2) + return 0; + clang_analyzer_eval(x % y == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(y == 2); // expected-warning{{TRUE}} + return 0; +} + +int test_commutativity(int x, int y) { + if (x + y != 0) + return 0; + if (y != 0) + return 0; + clang_analyzer_eval(y + x == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} + return 0; +} + +int test_binop_when_height_is_2_r(int a, int x, int y, int z) { + switch (a) { + case 1: { + if (x + y + z != 0) + return 0; + if (z != 0) + return 0; + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} + break; + } + case 2: { + if (x + y + z != 0) + return 0; + if (y != 0) + return 0; + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} + break; + } + case 3: { + if (x + y + z != 0) + return 0; + if (x != 0) + return 0; + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(x == 0); // expected-warning{{TRUE}} + break; + } + case 4: { + if (x + y + z != 0) + return 0; + if (x + y != 0) + return 0; + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(x + y == 0); // expected-warning{{TRUE}} + break; + } + case 5: { + if (z != 0) + return 0; + if (x + y + z != 0) + return 0; + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + if (y != 0) + return 0; + clang_analyzer_eval(y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(z == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}} + break; + } + + } + return 0; +} Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -515,6 +515,7 @@ REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(ClassSet, EquivalenceClass) REGISTER_MAP_WITH_PROGRAMSTATE(DisequalityMap, EquivalenceClass, ClassSet) + namespace { /// This class encapsulates a set of symbols equal to each other. /// @@ -1552,7 +1553,31 @@ LLVM_NODISCARD inline ProgramStateRef setConstraint(ProgramStateRef State, SymbolRef Sym, RangeSet Constraint) { - return setConstraint(State, EquivalenceClass::find(State, Sym), Constraint); + assert(State); + + State = setConstraint(State, EquivalenceClass::find(State, Sym), Constraint); + if (!State) + return nullptr; + + ConstraintMap CM = getConstraintMap(State); + for (auto const &C : CM) { + const SymbolRef &ParentSym = C.first; + SValBuilder &SVB = getSValBuilder(); + + SVal SimplifiedParentVal = + SVB.simplifySVal(State, SVB.makeSymbolVal(ParentSym)); + + SymbolRef SimplifiedParentSym = SimplifiedParentVal.getAsSymbol(); + const RangeSet *ParentConstraint = getConstraint(State, ParentSym); + // Set the existing constraint on the newly simplified parent. + if (SimplifiedParentSym && ParentConstraint) + State = setConstraint( + State, + EquivalenceClass::find(State, SimplifiedParentVal.getAsSymbol()), + *ParentConstraint); + } + + return State; } }; @@ -1588,6 +1613,8 @@ inline EquivalenceClass EquivalenceClass::find(ProgramStateRef State, SymbolRef Sym) { + assert(State && "State should not be null"); + assert(Sym && "Symbol should not be null"); // We store far from all Symbol -> Class mappings if (const EquivalenceClass *NontrivialClass = State->get<ClassMap>(Sym)) return *NontrivialClass;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits