From: Gabor Marton Date: Fri, 27 May 2022 18:44:43 +0000 (+0200) Subject: [analyzer] Track assume call stack to detect fixpoint X-Git-Tag: upstream/15.0.7~5703 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f66f4d3b07b2226cf14bd7a0f2056dfb2d26a89f;p=platform%2Fupstream%2Fllvm.git [analyzer] Track assume call stack to detect fixpoint Assume functions might recurse (see `reAssume` or `tryRearrange`). During the recursion, the State might not change anymore, that means we reached a fixpoint. In this patch, we avoid infinite recursion of assume calls by checking already visited States on the stack of assume function calls. This patch renders the previous "workaround" solution (D47155) unnecessary. Note that this is not an NFC patch. If we were to limit the maximum stack depth of the assume calls to 1 then would it be equivalent with the previous solution in D47155. Additionally, in D113753, we simplify the symbols right at the beginning of evalBinOpNN. So, a call to `simplifySVal` in `getKnownValue` (added in D51252) is no longer needed. Fixes https://github.com/llvm/llvm-project/issues/55851 Differential Revision: https://reviews.llvm.org/D126560 --- diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index d1e0629..de08ac5 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -144,6 +144,20 @@ protected: /// but not thread-safe. bool NotifyAssumeClients = true; + /// A helper class to simulate the call stack of nested assume calls. + class AssumeStackTy { + public: + void push(const ProgramState *S) { Aux.push_back(S); } + void pop() { Aux.pop_back(); } + bool contains(const ProgramState *S) const { + return llvm::is_contained(Aux, S); + } + + private: + llvm::SmallVector Aux; + }; + AssumeStackTy AssumeStack; + virtual ProgramStateRef assumeInternal(ProgramStateRef state, DefinedSVal Cond, bool Assumption) = 0; diff --git a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp index 8b04d3d..bfda967 100644 --- a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/ScopeExit.h" using namespace clang; using namespace ento; @@ -49,6 +50,18 @@ ConstraintManager::assumeDualImpl(ProgramStateRef &State, if (State->isPosteriorlyOverconstrained()) return {State, State}; + // Assume functions might recurse (see `reAssume` or `tryRearrange`). During + // the recursion the State might not change anymore, that means we reached a + // fixpoint. + // We avoid infinite recursion of assume calls by checking already visited + // States on the stack of assume function calls. + const ProgramState *RawSt = State.get(); + if (LLVM_UNLIKELY(AssumeStack.contains(RawSt))) + return {State, State}; + AssumeStack.push(RawSt); + auto AssumeStackBuilder = + llvm::make_scope_exit([this]() { AssumeStack.pop(); }); + ProgramStateRef StTrue = Assume(true); if (!StTrue) { diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 1232dcc..3922511 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -320,7 +320,6 @@ static NonLoc doRearrangeUnchecked(ProgramStateRef State, else llvm_unreachable("Operation not suitable for unchecked rearrangement!"); - // FIXME: Can we use assume() without getting into an infinite recursion? if (LSym == RSym) return SVB.evalBinOpNN(State, Op, nonloc::ConcreteInt(LInt), nonloc::ConcreteInt(RInt), ResultTy) @@ -1190,7 +1189,6 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, SVal V) { - V = simplifySVal(state, V); if (V.isUnknownOrUndef()) return nullptr; @@ -1384,14 +1382,6 @@ SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) { SVal VisitSVal(SVal V) { return V; } }; - // A crude way of preventing this function from calling itself from evalBinOp. - static bool isReentering = false; - if (isReentering) - return V; - - isReentering = true; SVal SimplifiedV = Simplifier(State).Visit(V); - isReentering = false; - return SimplifiedV; }