diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-04 19:20:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-08 19:02:26 +0000 |
commit | 81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch) | |
tree | 311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp | |
parent | 5fff09660e06a66bed6482da9c70df328e16bbb6 (diff) | |
parent | 145449b1e420787bb99721a429341fa6be3adfb6 (diff) |
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp index d642c3530268..9ef3455a110a 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ b/contrib/llvm-project/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; @@ -41,3 +42,82 @@ ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State, return ConditionTruthVal(true); return {}; } + +template <typename AssumeFunction> +ConstraintManager::ProgramStatePair +ConstraintManager::assumeDualImpl(ProgramStateRef &State, + AssumeFunction &Assume) { + if (LLVM_UNLIKELY(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) { + ProgramStateRef StFalse = Assume(false); + if (LLVM_UNLIKELY(!StFalse)) { // both infeasible + ProgramStateRef StInfeasible = State->cloneAsPosteriorlyOverconstrained(); + assert(StInfeasible->isPosteriorlyOverconstrained()); + // Checkers might rely on the API contract that both returned states + // cannot be null. Thus, we return StInfeasible for both branches because + // it might happen that a Checker uncoditionally uses one of them if the + // other is a nullptr. This may also happen with the non-dual and + // adjacent `assume(true)` and `assume(false)` calls. By implementing + // assume in therms of assumeDual, we can keep our API contract there as + // well. + return ProgramStatePair(StInfeasible, StInfeasible); + } + return ProgramStatePair(nullptr, StFalse); + } + + ProgramStateRef StFalse = Assume(false); + if (!StFalse) { + return ProgramStatePair(StTrue, nullptr); + } + + return ProgramStatePair(StTrue, StFalse); +} + +ConstraintManager::ProgramStatePair +ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) { + auto AssumeFun = [&](bool Assumption) { + return assumeInternal(State, Cond, Assumption); + }; + return assumeDualImpl(State, AssumeFun); +} + +ConstraintManager::ProgramStatePair +ConstraintManager::assumeInclusiveRangeDual(ProgramStateRef State, NonLoc Value, + const llvm::APSInt &From, + const llvm::APSInt &To) { + auto AssumeFun = [&](bool Assumption) { + return assumeInclusiveRangeInternal(State, Value, From, To, Assumption); + }; + return assumeDualImpl(State, AssumeFun); +} + +ProgramStateRef ConstraintManager::assume(ProgramStateRef State, + DefinedSVal Cond, bool Assumption) { + ConstraintManager::ProgramStatePair R = assumeDual(State, Cond); + return Assumption ? R.first : R.second; +} + +ProgramStateRef +ConstraintManager::assumeInclusiveRange(ProgramStateRef State, NonLoc Value, + const llvm::APSInt &From, + const llvm::APSInt &To, bool InBound) { + ConstraintManager::ProgramStatePair R = + assumeInclusiveRangeDual(State, Value, From, To); + return InBound ? R.first : R.second; +} |