23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/Support/raw_ostream.h" 26 using namespace clang;
30 class ArrayBoundCheckerV2 :
31 public Checker<check::Location> {
32 mutable std::unique_ptr<BuiltinBug> BT;
34 enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
40 void checkLocation(
SVal l,
bool isLoad,
const Stmt*S,
45 class RegionRawOffsetV2 {
51 : baseRegion(nullptr), byteOffset(
UnknownVal()) {}
55 : baseRegion(base), byteOffset(offset) {}
58 const SubRegion *getRegion()
const {
return baseRegion; }
65 void dumpToStream(raw_ostream &os)
const;
72 if (SR->
getKind() == MemRegion::UnknownSpaceRegionKind)
82 static std::pair<NonLoc, nonloc::ConcreteInt>
86 if (SymVal && SymVal->isExpression()) {
87 if (
const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) {
88 llvm::APSInt constant =
90 switch (SIE->getOpcode()) {
94 if ((extent.
getValue() % constant) != 0)
95 return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
111 return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
114 void ArrayBoundCheckerV2::checkLocation(
SVal location,
bool isLoad,
131 const RegionRawOffsetV2 &rawOffset =
132 RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
134 if (!rawOffset.getRegion())
137 NonLoc rawOffsetVal = rawOffset.getByteOffset();
147 std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
151 rawOffsetVal = simplifiedOffsets.first;
152 *NV = simplifiedOffsets.second;
155 SVal lowerBound = svalBuilder.
evalBinOpNN(state, BO_LT, rawOffsetVal, *NV,
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;
181 rawOffset.getRegion()->getExtent(svalBuilder);
186 std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
190 rawOffsetVal = simplifiedOffsets.first;
191 extentVal = simplifiedOffsets.second;
199 if (!upperboundToCheck)
203 std::tie(state_exceedsUpperBound, state_withinUpperBound) =
204 state->assume(*upperboundToCheck);
207 if (state_exceedsUpperBound && state_withinUpperBound) {
208 if (state->isTainted(rawOffset.getByteOffset())) {
209 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
212 }
else if (state_exceedsUpperBound) {
215 assert(!state_withinUpperBound);
216 reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
220 assert(state_withinUpperBound);
221 state = state_withinUpperBound;
225 if (state != originalState)
229 void ArrayBoundCheckerV2::reportOOB(
CheckerContext &checkerContext,
231 OOB_Kind
kind)
const {
238 BT.reset(
new BuiltinBug(
this,
"Out-of-bound access"));
244 llvm::raw_svector_ostream os(buf);
245 os <<
"Out of bound memory access ";
248 os <<
"(accessed memory precedes memory block)";
251 os <<
"(access exceeds upper limit of memory block)";
254 os <<
"(index is tainted)";
259 llvm::make_unique<BugReport>(*BT, os.str(), errorNode));
264 dumpToStream(llvm::errs());
267 void RegionRawOffsetV2::dumpToStream(raw_ostream &os)
const {
268 os <<
"raw_offset_v2{" << getRegion() <<
',' << getByteOffset() <<
'}';
315 if (
const SubRegion *subReg = dyn_cast<SubRegion>(region)) {
316 offset =
getValue(offset, svalBuilder);
318 return RegionRawOffsetV2(subReg, offset);
320 return RegionRawOffsetV2();
322 case MemRegion::ElementRegionKind: {
325 if (!index.getAs<
NonLoc>())
326 return RegionRawOffsetV2();
331 return RegionRawOffsetV2();
343 return RegionRawOffsetV2();
350 return RegionRawOffsetV2();
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getArrayIndexType() const
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
static SVal addValue(ProgramStateRef state, SVal x, SVal y, SValBuilder &svalBuilder)
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Stmt - This represents one statement.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Value representing integer constant.
NonLoc makeArrayIndex(uint64_t idx)
QualType getElementType() const
const MemRegion * getSuperRegion() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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)
A record of the "type" of an APSInt, used for conversions.
Represents a symbolic expression like 'x' + 3.
const MemSpaceRegion * getMemorySpace() const
static SVal computeExtentBegin(SValBuilder &svalBuilder, const MemRegion *region)
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
QualType getConditionType() const
static SVal getValue(SVal val, SValBuilder &svalBuilder)
NonLoc makeZeroArrayIndex()
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
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)
const MemRegion * getAsRegion() const
ASTContext & getContext()
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
Dataflow Directional Tag Classes.
Represents symbolic expression.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
SubRegion - A region that subsets another larger region.
const ProgramStateRef & getState() const
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.
SValBuilder & getSValBuilder()
ElementRegin is used to represent both array elements and casts.
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.
const llvm::APSInt & getValue() const
bool isUnknownOrUndef() const