aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-04 19:20:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-08 19:02:26 +0000
commit81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch)
tree311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
parent5fff09660e06a66bed6482da9c70df328e16bbb6 (diff)
parent145449b1e420787bb99721a429341fa6be3adfb6 (diff)
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp80
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;
+}