1717#include " clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1818#include " clang/StaticAnalyzer/Core/Checker.h"
1919#include " clang/StaticAnalyzer/Core/CheckerManager.h"
20+ #include " clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
2021#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2122#include " clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2223#include " llvm/ADT/SmallString.h"
@@ -81,6 +82,42 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder,
8182 }
8283}
8384
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+
84121void ArrayBoundCheckerV2::checkLocation (SVal location, bool isLoad,
85122 const Stmt* LoadS,
86123 CheckerContext &checkerContext) const {
@@ -104,16 +141,26 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
104141 if (!rawOffset.getRegion ())
105142 return ;
106143
144+ NonLoc rawOffsetVal = rawOffset.getByteOffset ();
145+
107146 // CHECK LOWER BOUND: Is byteOffset < extent begin?
108147 // If so, we are doing a load/store
109148 // before the first valid offset in the memory region.
110149
111150 SVal extentBegin = computeExtentBegin (svalBuilder, rawOffset.getRegion ());
112151
113152 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 ());
117164
118165 Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs <NonLoc>();
119166 if (!lowerBoundToCheck)
@@ -142,10 +189,18 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
142189 if (!extentVal.getAs <NonLoc>())
143190 break ;
144191
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 ());
149204
150205 Optional<NonLoc> upperboundToCheck = upperbound.getAs <NonLoc>();
151206 if (!upperboundToCheck)
@@ -157,13 +212,13 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
157212
158213 // If we are under constrained and the index variables are tainted, report.
159214 if (state_exceedsUpperBound && state_withinUpperBound) {
160- if (state->isTainted (rawOffset.getByteOffset ()))
215+ if (state->isTainted (rawOffset.getByteOffset ())) {
161216 reportOOB (checkerContext, state_exceedsUpperBound, OOB_Tainted);
162217 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.
167222 assert (!state_withinUpperBound);
168223 reportOOB (checkerContext, state_exceedsUpperBound, OOB_Excedes);
169224 return ;
0 commit comments