23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/Support/raw_ostream.h" 26 using namespace clang;
28 using namespace taint;
31 class ArrayBoundCheckerV2 :
32 public Checker<check::Location> {
33 mutable std::unique_ptr<BuiltinBug> BT;
35 enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
38 std::unique_ptr<BugReporterVisitor> Visitor =
nullptr)
const;
41 void checkLocation(SVal l,
bool isLoad,
const Stmt*S,
42 CheckerContext &C)
const;
46 class RegionRawOffsetV2 {
48 const SubRegion *baseRegion;
52 : baseRegion(nullptr), byteOffset(UnknownVal()) {}
55 RegionRawOffsetV2(
const SubRegion* base, SVal offset)
56 : baseRegion(base), byteOffset(offset) {}
58 NonLoc getByteOffset()
const {
return byteOffset.castAs<NonLoc>(); }
59 const SubRegion *getRegion()
const {
return baseRegion; }
62 SValBuilder &svalBuilder,
66 void dumpToStream(raw_ostream &os)
const;
71 const MemRegion *region) {
72 const MemSpaceRegion *SR = region->getMemorySpace();
73 if (SR->getKind() == MemRegion::UnknownSpaceRegionKind)
76 return svalBuilder.makeZeroArrayIndex();
83 static std::pair<NonLoc, nonloc::ConcreteInt>
85 SValBuilder &svalBuilder) {
87 if (SymVal && SymVal->isExpression()) {
88 if (
const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) {
89 llvm::APSInt constant =
90 APSIntType(extent.getValue()).convert(SIE->getRHS());
91 switch (SIE->getOpcode()) {
95 if ((extent.getValue() % constant) != 0)
96 return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
99 nonloc::SymbolVal(SIE->getLHS()),
100 svalBuilder.makeIntVal(extent.getValue() / constant),
104 nonloc::SymbolVal(SIE->getLHS()),
105 svalBuilder.makeIntVal(extent.getValue() - constant), svalBuilder);
112 return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
115 void ArrayBoundCheckerV2::checkLocation(SVal location,
bool isLoad,
117 CheckerContext &checkerContext)
const {
130 SValBuilder &svalBuilder = checkerContext.getSValBuilder();
131 const RegionRawOffsetV2 &rawOffset =
132 RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
134 if (!rawOffset.getRegion())
137 NonLoc rawOffsetVal = rawOffset.getByteOffset();
146 if (NV->getAs<nonloc::ConcreteInt>()) {
147 std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
149 NV->castAs<nonloc::ConcreteInt>(),
151 rawOffsetVal = simplifiedOffsets.first;
152 *NV = simplifiedOffsets.second;
155 SVal lowerBound = svalBuilder.evalBinOpNN(state, BO_LT, rawOffsetVal, *NV,
156 svalBuilder.getConditionType());
159 if (!lowerBoundToCheck)
163 std::tie(state_precedesLowerBound, state_withinLowerBound) =
164 state->assume(*lowerBoundToCheck);
167 if (state_precedesLowerBound && !state_withinLowerBound) {
168 reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
173 assert(state_withinLowerBound);
174 state = state_withinLowerBound;
180 DefinedOrUnknownSVal extentVal =
181 rawOffset.getRegion()->getExtent(svalBuilder);
182 if (!extentVal.getAs<NonLoc>())
185 if (extentVal.getAs<nonloc::ConcreteInt>()) {
186 std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
188 extentVal.castAs<nonloc::ConcreteInt>(),
190 rawOffsetVal = simplifiedOffsets.first;
191 extentVal = simplifiedOffsets.second;
194 SVal upperbound = svalBuilder.evalBinOpNN(state, BO_GE, rawOffsetVal,
195 extentVal.castAs<NonLoc>(),
196 svalBuilder.getConditionType());
199 if (!upperboundToCheck)
203 std::tie(state_exceedsUpperBound, state_withinUpperBound) =
204 state->assume(*upperboundToCheck);
207 if (state_exceedsUpperBound && state_withinUpperBound) {
208 SVal ByteOffset = rawOffset.getByteOffset();
210 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted,
211 llvm::make_unique<TaintBugVisitor>(ByteOffset));
214 }
else if (state_exceedsUpperBound) {
217 assert(!state_withinUpperBound);
218 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
222 assert(state_withinUpperBound);
223 state = state_withinUpperBound;
227 checkerContext.addTransition(state);
230 void ArrayBoundCheckerV2::reportOOB(
232 std::unique_ptr<BugReporterVisitor> Visitor)
const {
234 ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState);
239 BT.reset(
new BuiltinBug(
this,
"Out-of-bound access"));
245 llvm::raw_svector_ostream os(buf);
246 os <<
"Out of bound memory access ";
249 os <<
"(accessed memory precedes memory block)";
252 os <<
"(access exceeds upper limit of memory block)";
255 os <<
"(index is tainted)";
259 auto BR = llvm::make_unique<BugReport>(*BT, os.str(), errorNode);
260 BR->addVisitor(std::move(Visitor));
261 checkerContext.emitReport(std::move(BR));
266 dumpToStream(llvm::errs());
269 void RegionRawOffsetV2::dumpToStream(raw_ostream &os)
const {
270 os <<
"raw_offset_v2{" << getRegion() <<
',' << getByteOffset() <<
'}';
277 static inline SVal
getValue(SVal val, SValBuilder &svalBuilder) {
278 return val.getAs<UndefinedVal>() ? svalBuilder.makeArrayIndex(0) : val;
286 return sb.evalBinOpNN(state, BO_Mul, baseVal,
288 sb.getArrayIndexType());
294 SValBuilder &svalBuilder) {
297 if (x.isUnknownOrUndef() || y.isUnknownOrUndef())
300 return svalBuilder.evalBinOpNN(state, BO_Add, x.castAs<NonLoc>(),
302 svalBuilder.getArrayIndexType());
308 SValBuilder &svalBuilder,
311 const MemRegion *region = location.getAsRegion();
312 SVal offset = UndefinedVal();
315 switch (region->getKind()) {
317 if (
const SubRegion *subReg = dyn_cast<SubRegion>(region)) {
318 offset =
getValue(offset, svalBuilder);
319 if (!offset.isUnknownOrUndef())
320 return RegionRawOffsetV2(subReg, offset);
322 return RegionRawOffsetV2();
324 case MemRegion::ElementRegionKind: {
325 const ElementRegion *elemReg = cast<ElementRegion>(region);
326 SVal index = elemReg->getIndex();
327 if (!index.getAs<NonLoc>())
328 return RegionRawOffsetV2();
329 QualType elemType = elemReg->getElementType();
331 ASTContext &astContext = svalBuilder.getContext();
333 return RegionRawOffsetV2();
339 index.castAs<NonLoc>(),
344 if (offset.isUnknownOrUndef())
345 return RegionRawOffsetV2();
347 region = elemReg->getSuperRegion();
352 return RegionRawOffsetV2();
355 void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) {
356 mgr.registerChecker<ArrayBoundCheckerV2>();
359 bool ento::shouldRegisterArrayBoundCheckerV2(
const LangOptions &LO) {
A (possibly-)qualified type.
static SVal addValue(ProgramStateRef state, SVal x, SVal y, SValBuilder &svalBuilder)
Stmt - This represents one statement.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
CharUnits - This is an opaque type for sizes expressed in character units.
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
static SVal computeExtentBegin(SValBuilder &svalBuilder, const MemRegion *region)
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static SVal getValue(SVal val, SValBuilder &svalBuilder)
bool isTainted(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Check if the statement has a tainted value in the given state.
static SVal scaleValue(ProgramStateRef state, NonLoc baseVal, CharUnits scaling, SValBuilder &sb)
Dataflow Directional Tag Classes.
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types...
unsigned kind
All of the diagnostics that can be emitted by the frontend.
static std::pair< NonLoc, nonloc::ConcreteInt > getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent, SValBuilder &svalBuilder)
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.