llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
Gabor Marton 32f189b0d9 [analyzer] Implement assumeInclusiveRange in terms of assumeInclusiveRangeDual
Depends on D124758. This is the very same thing we have done for
assumeDual, but this time we do it for assumeInclusiveRange. This patch
is basically a no-brainer copy of that previous patch.

Differential Revision:
https://reviews.llvm.org/D125892
2022-05-23 09:32:44 +02:00

120 lines
4.9 KiB
C++

//===- ConstraintManager.cpp - Constraints on symbolic values. ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defined the interface to manage constraints on symbolic values.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/AST/Type.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
using namespace clang;
using namespace ento;
ConstraintManager::~ConstraintManager() = default;
static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
SymbolRef Sym) {
const MemRegion *R =
State->getStateManager().getRegionManager().getSymbolicRegion(Sym);
return loc::MemRegionVal(R);
}
ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
SymbolRef Sym) {
QualType Ty = Sym->getType();
DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
: nonloc::SymbolVal(Sym);
const ProgramStatePair &P = assumeDual(State, V);
if (P.first && !P.second)
return ConditionTruthVal(false);
if (!P.first && P.second)
return ConditionTruthVal(true);
return {};
}
ConstraintManager::ProgramStatePair
ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) {
ProgramStateRef StTrue = assumeInternal(State, Cond, true);
if (!StTrue) {
ProgramStateRef StFalse = assumeInternal(State, Cond, 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 = assumeInternal(State, Cond, false);
if (!StFalse) {
return ProgramStatePair(StTrue, nullptr);
}
return ProgramStatePair(StTrue, StFalse);
}
ConstraintManager::ProgramStatePair
ConstraintManager::assumeInclusiveRangeDual(ProgramStateRef State, NonLoc Value,
const llvm::APSInt &From,
const llvm::APSInt &To) {
ProgramStateRef StInRange =
assumeInclusiveRangeInternal(State, Value, From, To, true);
if (!StInRange) {
ProgramStateRef StOutOfRange =
assumeInclusiveRangeInternal(State, Value, From, To, false);
if (LLVM_UNLIKELY(!StOutOfRange)) { // 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);
}
}
ProgramStateRef StOutOfRange =
assumeInclusiveRangeInternal(State, Value, From, To, false);
if (!StOutOfRange) {
return ProgramStatePair(StInRange, nullptr);
}
return ProgramStatePair(StInRange, StOutOfRange);
}
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;
}