17
17
#include " clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18
18
#include " clang/StaticAnalyzer/Core/Checker.h"
19
19
#include " clang/StaticAnalyzer/Core/CheckerManager.h"
20
+ #include " clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
20
21
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21
22
#include " clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22
23
#include " llvm/ADT/SmallString.h"
@@ -81,6 +82,42 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder,
81
82
}
82
83
}
83
84
85
+ // TODO: once the constraint manager is smart enough to handle non simplified
86
+ // symbolic expressions remove this function. Note that this can not be used in
87
+ // the constraint manager as is, since this does not handle overflows. It is
88
+ // safe to assume, however, that memory offsets will not overflow.
89
+ static std::pair<NonLoc, nonloc::ConcreteInt>
90
+ getSimplifiedOffsets (NonLoc offset, nonloc::ConcreteInt extent,
91
+ SValBuilder &svalBuilder) {
92
+ Optional<nonloc::SymbolVal> SymVal = offset.getAs <nonloc::SymbolVal>();
93
+ if (SymVal && SymVal->isExpression ()) {
94
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol ())) {
95
+ llvm::APSInt constant =
96
+ APSIntType (extent.getValue ()).convert (SIE->getRHS ());
97
+ switch (SIE->getOpcode ()) {
98
+ case BO_Mul:
99
+ // The constant should never be 0 here, since it the result of scaling
100
+ // based on the size of a type which is never 0.
101
+ if ((extent.getValue () % constant) != 0 )
102
+ return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
103
+ else
104
+ return getSimplifiedOffsets (
105
+ nonloc::SymbolVal (SIE->getLHS ()),
106
+ svalBuilder.makeIntVal (extent.getValue () / constant),
107
+ svalBuilder);
108
+ case BO_Add:
109
+ return getSimplifiedOffsets (
110
+ nonloc::SymbolVal (SIE->getLHS ()),
111
+ svalBuilder.makeIntVal (extent.getValue () - constant), svalBuilder);
112
+ default :
113
+ break ;
114
+ }
115
+ }
116
+ }
117
+
118
+ return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
119
+ }
120
+
84
121
void ArrayBoundCheckerV2::checkLocation (SVal location, bool isLoad,
85
122
const Stmt* LoadS,
86
123
CheckerContext &checkerContext) const {
@@ -104,16 +141,26 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
104
141
if (!rawOffset.getRegion ())
105
142
return ;
106
143
144
+ NonLoc rawOffsetVal = rawOffset.getByteOffset ();
145
+
107
146
// CHECK LOWER BOUND: Is byteOffset < extent begin?
108
147
// If so, we are doing a load/store
109
148
// before the first valid offset in the memory region.
110
149
111
150
SVal extentBegin = computeExtentBegin (svalBuilder, rawOffset.getRegion ());
112
151
113
152
if (Optional<NonLoc> NV = extentBegin.getAs <NonLoc>()) {
114
- SVal lowerBound =
115
- svalBuilder.evalBinOpNN (state, BO_LT, rawOffset.getByteOffset (), *NV,
116
- svalBuilder.getConditionType ());
153
+ if (NV->getAs <nonloc::ConcreteInt>()) {
154
+ std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
155
+ getSimplifiedOffsets (rawOffset.getByteOffset (),
156
+ NV->castAs <nonloc::ConcreteInt>(),
157
+ svalBuilder);
158
+ rawOffsetVal = simplifiedOffsets.first ;
159
+ *NV = simplifiedOffsets.second ;
160
+ }
161
+
162
+ SVal lowerBound = svalBuilder.evalBinOpNN (state, BO_LT, rawOffsetVal, *NV,
163
+ svalBuilder.getConditionType ());
117
164
118
165
Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs <NonLoc>();
119
166
if (!lowerBoundToCheck)
@@ -142,10 +189,18 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
142
189
if (!extentVal.getAs <NonLoc>())
143
190
break ;
144
191
145
- SVal upperbound
146
- = svalBuilder.evalBinOpNN (state, BO_GE, rawOffset.getByteOffset (),
147
- extentVal.castAs <NonLoc>(),
148
- svalBuilder.getConditionType ());
192
+ if (extentVal.getAs <nonloc::ConcreteInt>()) {
193
+ std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
194
+ getSimplifiedOffsets (rawOffset.getByteOffset (),
195
+ extentVal.castAs <nonloc::ConcreteInt>(),
196
+ svalBuilder);
197
+ rawOffsetVal = simplifiedOffsets.first ;
198
+ extentVal = simplifiedOffsets.second ;
199
+ }
200
+
201
+ SVal upperbound = svalBuilder.evalBinOpNN (state, BO_GE, rawOffsetVal,
202
+ extentVal.castAs <NonLoc>(),
203
+ svalBuilder.getConditionType ());
149
204
150
205
Optional<NonLoc> upperboundToCheck = upperbound.getAs <NonLoc>();
151
206
if (!upperboundToCheck)
@@ -157,13 +212,13 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
157
212
158
213
// If we are under constrained and the index variables are tainted, report.
159
214
if (state_exceedsUpperBound && state_withinUpperBound) {
160
- if (state->isTainted (rawOffset.getByteOffset ()))
215
+ if (state->isTainted (rawOffset.getByteOffset ())) {
161
216
reportOOB (checkerContext, state_exceedsUpperBound, OOB_Tainted);
162
217
return ;
163
- }
164
-
165
- // If we are constrained enough to definitely exceed the upper bound, report.
166
- if (state_exceedsUpperBound) {
218
+ }
219
+ } else if (state_exceedsUpperBound) {
220
+ // If we are constrained enough to definitely exceed the upper bound,
221
+ // report.
167
222
assert (!state_withinUpperBound);
168
223
reportOOB (checkerContext, state_exceedsUpperBound, OOB_Excedes);
169
224
return ;
0 commit comments