diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -82,9 +82,8 @@ virtual bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const = 0; - virtual ProgramStateRef assume(ProgramStateRef state, - DefinedSVal Cond, - bool Assumption) = 0; + ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, + bool Assumption); using ProgramStatePair = std::pair; @@ -158,6 +157,9 @@ /// but not thread-safe. bool NotifyAssumeClients = true; + virtual ProgramStateRef assumeInternal(ProgramStateRef state, + DefinedSVal Cond, bool Assumption) = 0; + /// canReasonAbout - Not all ConstraintManagers can accurately reason about /// all SVal values. This method returns true if the ConstraintManager can /// reasonably handle a given SVal value. This is typically queried by diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h @@ -36,8 +36,8 @@ /// Ensures that the DefinedSVal conditional is expressed as a NonLoc by /// creating boolean casts to handle Loc's. - ProgramStateRef assume(ProgramStateRef State, DefinedSVal Cond, - bool Assumption) override; + ProgramStateRef assumeInternal(ProgramStateRef State, DefinedSVal Cond, + bool Assumption) override; ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, diff --git a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp --- a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -44,10 +44,10 @@ ConstraintManager::ProgramStatePair ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { - ProgramStateRef StTrue = assume(State, Cond, true); + ProgramStateRef StTrue = assumeInternal(State, Cond, true); if (!StTrue) { - ProgramStateRef StFalse = assume(State, Cond, false); + ProgramStateRef StFalse = assumeInternal(State, Cond, false); if (!StFalse) { // both infeasible ProgramStateRef Infeasible = State->cloneAsInfeasible(); assert(Infeasible->isInfeasible()); @@ -56,10 +56,16 @@ return ProgramStatePair(nullptr, StFalse); } - ProgramStateRef StFalse = assume(State, Cond, false); + ProgramStateRef StFalse = assumeInternal(State, Cond, false); if (!StFalse) { return ProgramStatePair(StTrue, nullptr); } return ProgramStatePair(StTrue, StFalse); } + +ProgramStateRef ConstraintManager::assume(ProgramStateRef State, + DefinedSVal Cond, bool Assumption) { + ConstraintManager::ProgramStatePair R = assumeDual(State, Cond); + return Assumption ? R.first : R.second; +} diff --git a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp --- a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -22,9 +22,9 @@ SimpleConstraintManager::~SimpleConstraintManager() {} -ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State, - DefinedSVal Cond, - bool Assumption) { +ProgramStateRef SimpleConstraintManager::assumeInternal(ProgramStateRef State, + DefinedSVal Cond, + bool Assumption) { // If we have a Loc value, cast it to a bool NonLoc first. if (Optional LV = Cond.getAs()) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); @@ -86,8 +86,8 @@ } case nonloc::LocAsIntegerKind: - return assume(State, Cond.castAs().getLoc(), - Assumption); + return assumeInternal(State, Cond.castAs().getLoc(), + Assumption); } // end switch } diff --git a/clang/test/Analysis/infeasible-crash.c b/clang/test/Analysis/infeasible-crash.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/infeasible-crash.c @@ -0,0 +1,38 @@ +// RUN: %clang_analyze_cc1 %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=alpha.unix.cstring.OutOfBounds,alpha.unix.cstring.UninitializedRead \ +// RUN: -analyzer-checker=debug.ExprInspection \ +// RUN: -analyzer-config eagerly-assume=false \ +// RUN: -verify + +// expected-no-diagnostics + +void *memmove(void *, const void *, unsigned long); + +typedef struct { + char a[1024]; +} b; +int c; +b *invalidate(); +int d() { + b *a = invalidate(); + if (c < 1024) + return 0; + int f = c & ~3, g = f; + g--; + if (g) + return 0; + + // Parent state is already infeasible. + // clang_analyzer_printState(); + // "constraints": [ + // { "symbol": "(derived_$3{conj_$0{int, LC1, S728, #1},c}) & -4", "range": "{ [1, 1] }" }, + // { "symbol": "derived_$3{conj_$0{int, LC1, S728, #1},c}", "range": "{ [1024, 2147483647] }" } + // ], + + // This sould not crash! + // It crashes in baseline, since there both true and false states are nullptr! + memmove(a->a, &a->a[f], c - f); + + return 0; +} diff --git a/clang/test/Analysis/sink-infeasible.c b/clang/test/Analysis/infeasible-sink.c rename from clang/test/Analysis/sink-infeasible.c rename to clang/test/Analysis/infeasible-sink.c