22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
29 class ArrayBoundCheckerV2 :
30 public Checker<check::Location> {
31 mutable std::unique_ptr<BuiltinBug> BT;
33 enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
39 void checkLocation(
SVal l,
bool isLoad,
const Stmt*
S,
44 class RegionRawOffsetV2 {
50 : baseRegion(nullptr), byteOffset(
UnknownVal()) {}
54 : baseRegion(base), byteOffset(offset) {}
57 const SubRegion *getRegion()
const {
return baseRegion; }
64 void dumpToStream(raw_ostream &os)
const;
79 region = cast<SubRegion>(region)->getSuperRegion();
84 void ArrayBoundCheckerV2::checkLocation(
SVal location,
bool isLoad,
101 const RegionRawOffsetV2 &rawOffset =
102 RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
104 if (!rawOffset.getRegion())
119 if (!lowerBoundToCheck)
123 std::tie(state_precedesLowerBound, state_withinLowerBound) =
124 state->assume(*lowerBoundToCheck);
127 if (state_precedesLowerBound && !state_withinLowerBound) {
128 reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
133 assert(state_withinLowerBound);
134 state = state_withinLowerBound;
141 rawOffset.getRegion()->getExtent(svalBuilder);
151 if (!upperboundToCheck)
155 std::tie(state_exceedsUpperBound, state_withinUpperBound) =
156 state->assume(*upperboundToCheck);
159 if (state_exceedsUpperBound && state_withinUpperBound) {
160 if (state->isTainted(rawOffset.getByteOffset()))
161 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
166 if (state_exceedsUpperBound) {
167 assert(!state_withinUpperBound);
168 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
172 assert(state_withinUpperBound);
173 state = state_withinUpperBound;
177 if (state != originalState)
181 void ArrayBoundCheckerV2::reportOOB(
CheckerContext &checkerContext,
183 OOB_Kind
kind)
const {
190 BT.reset(
new BuiltinBug(
this,
"Out-of-bound access"));
196 llvm::raw_svector_ostream os(buf);
197 os <<
"Out of bound memory access ";
200 os <<
"(accessed memory precedes memory block)";
203 os <<
"(access exceeds upper limit of memory block)";
206 os <<
"(index is tainted)";
211 llvm::make_unique<BugReport>(*BT, os.str(), errorNode));
215 dumpToStream(llvm::errs());
218 void RegionRawOffsetV2::dumpToStream(raw_ostream &os)
const {
219 os <<
"raw_offset_v2{" << getRegion() <<
',' << getByteOffset() <<
'}';
256 RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(
ProgramStateRef state,
266 if (
const SubRegion *subReg = dyn_cast<SubRegion>(region)) {
267 offset =
getValue(offset, svalBuilder);
269 return RegionRawOffsetV2(subReg, offset);
271 return RegionRawOffsetV2();
276 if (!index.getAs<
NonLoc>())
277 return RegionRawOffsetV2();
282 return RegionRawOffsetV2();
294 return RegionRawOffsetV2();
301 return RegionRawOffsetV2();
MemRegion - The root abstract class for all memory regions.
static SVal addValue(ProgramStateRef state, SVal x, SVal y, SValBuilder &svalBuilder)
QualType getArrayIndexType() const
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
NonLoc makeArrayIndex(uint64_t idx)
QualType getElementType() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
bool isUnknownOrUndef() const
bool isIncompleteType(NamedDecl **Def=nullptr) const
Def If non-NULL, and the type refers to some kind of declaration that can be completed (such as a C s...
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const MemRegion * getSuperRegion() const
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
static SVal computeExtentBegin(SValBuilder &svalBuilder, const MemRegion *region)
const ProgramStateRef & getState() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
static SVal getValue(SVal val, SValBuilder &svalBuilder)
QualType getConditionType() const
NonLoc makeZeroArrayIndex()
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
static SVal scaleValue(ProgramStateRef state, NonLoc baseVal, CharUnits scaling, SValBuilder &sb)
ASTContext & getContext()
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
const MemRegion * getAsRegion() const
static __inline__ uint32_t uint32_t y
unsigned kind
All of the diagnostics that can be emitted by the frontend.
SValBuilder & getSValBuilder()
ElementRegin is used to represent both array elements and casts.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.