1 | //== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines SimpleConstraintManager, a class that provides a |
10 | // simplified constraint manager interface, compared to ConstraintManager. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h" |
15 | #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" |
16 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
17 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
18 | #include <optional> |
19 | |
20 | namespace clang { |
21 | |
22 | namespace ento { |
23 | |
24 | SimpleConstraintManager::~SimpleConstraintManager() {} |
25 | |
26 | ProgramStateRef SimpleConstraintManager::assumeInternal(ProgramStateRef State, |
27 | DefinedSVal Cond, |
28 | bool Assumption) { |
29 | // If we have a Loc value, cast it to a bool NonLoc first. |
30 | if (std::optional<Loc> LV = Cond.getAs<Loc>()) { |
31 | SValBuilder &SVB = State->getStateManager().getSValBuilder(); |
32 | QualType T; |
33 | const MemRegion *MR = LV->getAsRegion(); |
34 | if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(Val: MR)) |
35 | T = TR->getLocationType(); |
36 | else |
37 | T = SVB.getContext().VoidPtrTy; |
38 | |
39 | Cond = SVB.evalCast(V: *LV, CastTy: SVB.getContext().BoolTy, OriginalTy: T).castAs<DefinedSVal>(); |
40 | } |
41 | |
42 | return assume(State, Cond: Cond.castAs<NonLoc>(), Assumption); |
43 | } |
44 | |
45 | ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State, |
46 | NonLoc Cond, bool Assumption) { |
47 | State = assumeAux(State, Cond, Assumption); |
48 | if (EE) |
49 | return EE->processAssume(state: State, cond: Cond, assumption: Assumption); |
50 | return State; |
51 | } |
52 | |
53 | ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State, |
54 | NonLoc Cond, |
55 | bool Assumption) { |
56 | |
57 | // We cannot reason about SymSymExprs, and can only reason about some |
58 | // SymIntExprs. |
59 | if (!canReasonAbout(X: Cond)) { |
60 | // Just add the constraint to the expression without trying to simplify. |
61 | SymbolRef Sym = Cond.getAsSymbol(); |
62 | assert(Sym); |
63 | return assumeSymUnsupported(State, Sym, Assumption); |
64 | } |
65 | |
66 | switch (Cond.getKind()) { |
67 | default: |
68 | llvm_unreachable("'Assume' not implemented for this NonLoc" ); |
69 | |
70 | case nonloc::SymbolValKind: { |
71 | nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>(); |
72 | SymbolRef Sym = SV.getSymbol(); |
73 | assert(Sym); |
74 | return assumeSym(State, Sym, Assumption); |
75 | } |
76 | |
77 | case nonloc::ConcreteIntKind: { |
78 | bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0; |
79 | bool isFeasible = b ? Assumption : !Assumption; |
80 | return isFeasible ? State : nullptr; |
81 | } |
82 | |
83 | case nonloc::PointerToMemberKind: { |
84 | bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer(); |
85 | bool IsFeasible = IsNull ? Assumption : !Assumption; |
86 | return IsFeasible ? State : nullptr; |
87 | } |
88 | |
89 | case nonloc::LocAsIntegerKind: |
90 | return assumeInternal(State, Cond: Cond.castAs<nonloc::LocAsInteger>().getLoc(), |
91 | Assumption); |
92 | } // end switch |
93 | } |
94 | |
95 | ProgramStateRef SimpleConstraintManager::assumeInclusiveRangeInternal( |
96 | ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, |
97 | const llvm::APSInt &To, bool InRange) { |
98 | |
99 | assert(From.isUnsigned() == To.isUnsigned() && |
100 | From.getBitWidth() == To.getBitWidth() && |
101 | "Values should have same types!" ); |
102 | |
103 | if (!canReasonAbout(X: Value)) { |
104 | // Just add the constraint to the expression without trying to simplify. |
105 | SymbolRef Sym = Value.getAsSymbol(); |
106 | assert(Sym); |
107 | return assumeSymInclusiveRange(State, Sym, From, To, InRange); |
108 | } |
109 | |
110 | switch (Value.getKind()) { |
111 | default: |
112 | llvm_unreachable("'assumeInclusiveRange' is not implemented" |
113 | "for this NonLoc" ); |
114 | |
115 | case nonloc::LocAsIntegerKind: |
116 | case nonloc::SymbolValKind: { |
117 | if (SymbolRef Sym = Value.getAsSymbol()) |
118 | return assumeSymInclusiveRange(State, Sym, From, To, InRange); |
119 | return State; |
120 | } // end switch |
121 | |
122 | case nonloc::ConcreteIntKind: { |
123 | const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue(); |
124 | bool IsInRange = IntVal >= From && IntVal <= To; |
125 | bool isFeasible = (IsInRange == InRange); |
126 | return isFeasible ? State : nullptr; |
127 | } |
128 | } // end switch |
129 | } |
130 | |
131 | } // end of namespace ento |
132 | |
133 | } // end of namespace clang |
134 | |