aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp144
1 files changed, 100 insertions, 44 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 58d360a2e2db..45e48d435aca 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -28,7 +28,11 @@ class SimpleSValBuilder : public SValBuilder {
// returns NULL.
// This is an implementation detail. Checkers should use `getKnownValue()`
// instead.
- const llvm::APSInt *getConstValue(ProgramStateRef state, SVal V);
+ static const llvm::APSInt *getConstValue(ProgramStateRef state, SVal V);
+
+ // Helper function that returns the value stored in a nonloc::ConcreteInt or
+ // loc::ConcreteInt.
+ static const llvm::APSInt *getConcreteValue(SVal V);
// With one `simplifySValOnce` call, a compound symbols might collapse to
// simpler symbol tree that is still possible to further simplify. Thus, we
@@ -76,6 +80,16 @@ public:
/// (integer) value, that value is returned. Otherwise, returns NULL.
const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override;
+ /// Evaluates a given SVal by recursively evaluating and simplifying the
+ /// children SVals, then returns its minimal possible (integer) value. If the
+ /// constraint manager cannot provide a meaningful answer, this returns NULL.
+ const llvm::APSInt *getMinValue(ProgramStateRef state, SVal V) override;
+
+ /// Evaluates a given SVal by recursively evaluating and simplifying the
+ /// children SVals, then returns its maximal possible (integer) value. If the
+ /// constraint manager cannot provide a meaningful answer, this returns NULL.
+ const llvm::APSInt *getMaxValue(ProgramStateRef state, SVal V) override;
+
SVal simplifySVal(ProgramStateRef State, SVal V) override;
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
@@ -445,11 +459,11 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
while (true) {
- switch (lhs.getSubKind()) {
+ switch (lhs.getKind()) {
default:
return makeSymExprValNN(op, lhs, rhs, resultTy);
case nonloc::PointerToMemberKind: {
- assert(rhs.getSubKind() == nonloc::PointerToMemberKind &&
+ assert(rhs.getKind() == nonloc::PointerToMemberKind &&
"Both SVals should have pointer-to-member-type");
auto LPTM = lhs.castAs<nonloc::PointerToMember>(),
RPTM = rhs.castAs<nonloc::PointerToMember>();
@@ -465,36 +479,36 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
case nonloc::LocAsIntegerKind: {
Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
- switch (rhs.getSubKind()) {
- case nonloc::LocAsIntegerKind:
- // FIXME: at the moment the implementation
- // of modeling "pointers as integers" is not complete.
- if (!BinaryOperator::isComparisonOp(op))
- return UnknownVal();
- return evalBinOpLL(state, op, lhsL,
- rhs.castAs<nonloc::LocAsInteger>().getLoc(),
- resultTy);
- case nonloc::ConcreteIntKind: {
- // FIXME: at the moment the implementation
- // of modeling "pointers as integers" is not complete.
- if (!BinaryOperator::isComparisonOp(op))
- return UnknownVal();
- // Transform the integer into a location and compare.
- // FIXME: This only makes sense for comparisons. If we want to, say,
- // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
- // then pack it back into a LocAsInteger.
- llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
- // If the region has a symbolic base, pay attention to the type; it
- // might be coming from a non-default address space. For non-symbolic
- // regions it doesn't matter that much because such comparisons would
- // most likely evaluate to concrete false anyway. FIXME: We might
- // still need to handle the non-comparison case.
- if (SymbolRef lSym = lhs.getAsLocSymbol(true))
- BasicVals.getAPSIntType(lSym->getType()).apply(i);
- else
- BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
- return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
- }
+ switch (rhs.getKind()) {
+ case nonloc::LocAsIntegerKind:
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
+ return evalBinOpLL(state, op, lhsL,
+ rhs.castAs<nonloc::LocAsInteger>().getLoc(),
+ resultTy);
+ case nonloc::ConcreteIntKind: {
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
+ // Transform the integer into a location and compare.
+ // FIXME: This only makes sense for comparisons. If we want to, say,
+ // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
+ // then pack it back into a LocAsInteger.
+ llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
+ // If the region has a symbolic base, pay attention to the type; it
+ // might be coming from a non-default address space. For non-symbolic
+ // regions it doesn't matter that much because such comparisons would
+ // most likely evaluate to concrete false anyway. FIXME: We might
+ // still need to handle the non-comparison case.
+ if (SymbolRef lSym = lhs.getAsLocSymbol(true))
+ BasicVals.getAPSIntType(lSym->getType()).apply(i);
+ else
+ BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
+ return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
+ }
default:
switch (op) {
case BO_EQ:
@@ -505,7 +519,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// This case also handles pointer arithmetic.
return makeSymExprValNN(op, InputLHS, InputRHS, resultTy);
}
- }
+ }
}
case nonloc::ConcreteIntKind: {
llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue();
@@ -529,8 +543,21 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
const llvm::APSInt *Result =
BasicVals.evalAPSInt(op, LHSValue, RHSValue);
- if (!Result)
+ if (!Result) {
+ if (op == BO_Shl || op == BO_Shr) {
+ // FIXME: At this point the constant folding claims that the result
+ // of a bitwise shift is undefined. However, constant folding
+ // relies on the inaccurate type information that is stored in the
+ // bit size of APSInt objects, and if we reached this point, then
+ // the checker core.BitwiseShift already determined that the shift
+ // is valid (in a PreStmt callback, by querying the real type from
+ // the AST node).
+ // To avoid embarrassing false positives, let's just say that we
+ // don't know anything about the result of the shift.
+ return UnknownVal();
+ }
return UndefinedVal();
+ }
return nonloc::ConcreteInt(*Result);
}
@@ -752,8 +779,7 @@ static void assertEqualBitWidths(ProgramStateRef State, Loc RhsLoc,
RhsLoc.getType(Ctx).isNull() ? 0 : Ctx.getTypeSize(RhsLoc.getType(Ctx));
uint64_t LhsBitwidth =
LhsLoc.getType(Ctx).isNull() ? 0 : Ctx.getTypeSize(LhsLoc.getType(Ctx));
- if (RhsBitwidth && LhsBitwidth &&
- (LhsLoc.getSubKind() == RhsLoc.getSubKind())) {
+ if (RhsBitwidth && LhsBitwidth && (LhsLoc.getKind() == RhsLoc.getKind())) {
assert(RhsBitwidth == LhsBitwidth &&
"RhsLoc and LhsLoc bitwidth must be same!");
}
@@ -799,7 +825,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
}
- switch (lhs.getSubKind()) {
+ switch (lhs.getKind()) {
default:
llvm_unreachable("Ordering not implemented for this Loc.");
@@ -1170,18 +1196,22 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
const llvm::APSInt *SimpleSValBuilder::getConstValue(ProgramStateRef state,
SVal V) {
- if (V.isUnknownOrUndef())
- return nullptr;
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymVal(state, Sym);
+
+ return nullptr;
+}
+
+const llvm::APSInt *SimpleSValBuilder::getConcreteValue(SVal V) {
if (std::optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
if (std::optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
return &X->getValue();
- if (SymbolRef Sym = V.getAsSymbol())
- return state->getConstraintManager().getSymVal(state, Sym);
-
return nullptr;
}
@@ -1190,6 +1220,32 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
return getConstValue(state, simplifySVal(state, V));
}
+const llvm::APSInt *SimpleSValBuilder::getMinValue(ProgramStateRef state,
+ SVal V) {
+ V = simplifySVal(state, V);
+
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymMinVal(state, Sym);
+
+ return nullptr;
+}
+
+const llvm::APSInt *SimpleSValBuilder::getMaxValue(ProgramStateRef state,
+ SVal V) {
+ V = simplifySVal(state, V);
+
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymMaxVal(state, Sym);
+
+ return nullptr;
+}
+
SVal SimpleSValBuilder::simplifyUntilFixpoint(ProgramStateRef State, SVal Val) {
SVal SimplifiedVal = simplifySValOnce(State, Val);
while (SimplifiedVal != Val) {
@@ -1359,7 +1415,7 @@ SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) {
SVal VisitMemRegion(const MemRegion *R) { return loc::MemRegionVal(R); }
- SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ SVal VisitSymbolVal(nonloc::SymbolVal V) {
// Simplification is much more costly than computing complexity.
// For high complexity, it may be not worth it.
return Visit(V.getSymbol());