;
42staticstd::optional<QualType> determineElementType(
const Expr*
E,
44 const auto*ASE = dyn_cast<ArraySubscriptExpr>(
E);
48 const MemRegion*SubscriptBaseReg =
C.getSVal(ASE->getBase()).getAsRegion();
49 if(!SubscriptBaseReg)
54 if(isa<ElementRegion>(SubscriptBaseReg->
StripCasts()))
57 returnASE->getType();
60staticstd::optional<int64_t>
61determineElementSize(
conststd::optional<QualType>
T,
const CheckerContext&
C) {
64 return C.getASTContext().getTypeSizeInChars(*T).getQuantity();
67classStateUpdateReporter {
69 const NonLocByteOffsetVal;
70 conststd::optional<QualType> ElementType;
71 conststd::optional<int64_t> ElementSize;
72 boolAssumedNonNegative =
false;
73std::optional<NonLoc> AssumedUpperBound = std::nullopt;
78: Reg(R), ByteOffsetVal(ByteOffsVal),
79ElementType(determineElementType(
E,
C)),
80ElementSize(determineElementSize(ElementType,
C)) {}
82 voidrecordNonNegativeAssumption() { AssumedNonNegative =
true; }
83 voidrecordUpperBoundAssumption(
NonLocUpperBoundVal) {
84AssumedUpperBound = UpperBoundVal;
87 boolassumedNonNegative() {
returnAssumedNonNegative; }
108 static boolprovidesInformationAboutInteresting(
SymbolRefSym,
110 static boolprovidesInformationAboutInteresting(
SValSV,
112 returnprovidesInformationAboutInteresting(SV.
getAsSymbol(), BR);
127classArrayBoundCheckerV2 :
public Checker<check::PostStmt<ArraySubscriptExpr>,
128check::PostStmt<UnaryOperator>,
129check::PostStmt<MemberExpr>> {
130 BugTypeBT{
this,
"Out-of-bound access"};
136 NonLocOffset, std::optional<NonLoc> Extent,
137 boolIsTaintBug =
false)
const;
152performCheck(
E,
C);
155 if(
E->getOpcode() == UO_Deref)
156performCheck(
E,
C);
160performCheck(
E->getBase(),
C);
171staticstd::optional<std::pair<const SubRegion *, NonLoc>>
183dyn_cast_or_null<ElementRegion>(Location.
getAsRegion());
201 autoDelta = EvalBinOp(BO_Mul, *Index, Size);
206Offset = EvalBinOp(BO_Add, *Offset, *Delta);
213CurRegion = dyn_cast_or_null<ElementRegion>(OwnerRegion);
217 returnstd::make_pair(OwnerRegion, *Offset);
242staticstd::pair<NonLoc, nonloc::ConcreteInt>
245 constllvm::APSInt &extentVal = extent.
getValue();
247 if(SymVal && SymVal->isExpression()) {
248 if(
const SymIntExpr*SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) {
250 switch(SIE->getOpcode()) {
254 if((extentVal % constant) != 0)
255 returnstd::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
259svalBuilder.
makeIntVal(extentVal / constant), svalBuilder);
263svalBuilder.
makeIntVal(extentVal - constant), svalBuilder);
270 returnstd::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
275 returnMaxV && MaxV->isNegative();
290staticstd::pair<ProgramStateRef, ProgramStateRef>
307 return{
nullptr, State};
310 return{State,
nullptr};
315 return{
nullptr, State};
329 autoBelowThreshold =
334 returnState->assume(*BelowThreshold);
336 return{
nullptr,
nullptr};
346 if(StringRef Name = FR->getDecl()->getName(); !Name.empty())
347 returnformatv(
"the field '{0}'", Name);
348 return "the unnamed field";
351 if(isa<AllocaRegion>(Region))
352 return "the memory returned by 'alloca'";
354 if(isa<SymbolicRegion>(Region) &&
356 return "the heap area";
358 if(isa<StringRegion>(Region))
359 return "the string literal";
361 return "the region";
366 returnConcreteVal->getValue()->tryExtValue();
376std::string RegName =
getRegionName(Region), OffsetStr =
"";
379OffsetStr = formatv(
" {0}", ConcreteOffset);
382formatv(
"Out of bound access to memory preceding {0}", RegName),
383formatv(
"Access of {0} at negative byte offset{1}", RegName, OffsetStr)};
391std::optional<int64_t> &Val2, int64_t Divisor) {
394 const boolVal1HasRemainder = Val1 && *Val1 % Divisor;
395 const boolVal2HasRemainder = Val2 && *Val2 % Divisor;
396 if(!Val1HasRemainder && !Val2HasRemainder) {
408 boolAlsoMentionUnderflow) {
411assert(EReg &&
"this checker only handles element access");
412 QualTypeElemType = EReg->getElementType();
419 boolUseByteOffsets = !
tryDividePair(OffsetN, ExtentN, ElemSize);
420 const char*OffsetOrIndex = UseByteOffsets ?
"byte offset":
"index";
423llvm::raw_svector_ostream Out(Buf);
424Out <<
"Access of ";
425 if(!ExtentN && !UseByteOffsets)
426Out <<
"'"<< ElemType.
getAsString() <<
"' element in ";
427Out << RegName <<
" at ";
428 if(AlsoMentionUnderflow) {
429Out <<
"a negative or overflowing "<< OffsetOrIndex;
430}
else if(OffsetN) {
431Out << OffsetOrIndex <<
" "<< *OffsetN;
433Out <<
"an overflowing "<< OffsetOrIndex;
436Out <<
", while it holds only ";
444Out <<
" '"<< ElemType.
getAsString() <<
"' element";
450 return{formatv(
"Out of bound access to memory {0} {1}",
451AlsoMentionUnderflow ?
"around":
"after the end of",
457 boolAlsoMentionUnderflow) {
459 return{formatv(
"Potential out of bound access to {0} with tainted {1}",
460RegName, OffsetName),
461formatv(
"Access of {0} with a tainted {1} that may be {2}too large",
463AlsoMentionUnderflow ?
"negative or ":
"")};
468 if(!AssumedNonNegative && !AssumedUpperBound)
472 returngetMessage(BR);
477 boolShouldReportNonNegative = AssumedNonNegative;
478 if(!providesInformationAboutInteresting(ByteOffsetVal, BR)) {
479 if(AssumedUpperBound &&
480providesInformationAboutInteresting(*AssumedUpperBound, BR)) {
484ShouldReportNonNegative =
false;
494 const boolUseIndex =
495ElementSize &&
tryDividePair(OffsetN, ExtentN, *ElementSize);
498llvm::raw_svector_ostream Out(Buf);
503Out <<
"'"<< OffsetN <<
"' ";
504}
else if(AssumedUpperBound) {
505Out <<
"byte offset ";
507Out <<
"'"<< OffsetN <<
"' ";
513 if(ShouldReportNonNegative) {
514Out <<
" non-negative";
516 if(AssumedUpperBound) {
517 if(ShouldReportNonNegative)
519Out <<
" less than ";
521Out << *ExtentN <<
", ";
522 if(UseIndex && ElementType)
523Out <<
"the number of '"<< ElementType->getAsString()
524<<
"' elements in ";
526Out <<
"the extent of ";
529 returnstd::string(Out.str());
532boolStateUpdateReporter::providesInformationAboutInteresting(
544 if(isa<SymSymExpr>(PartSym))
551 const SValLocation =
C.getSVal(
E);
558 if(isFromCtypeMacro(
E,
C.getASTContext()))
564 conststd::optional<std::pair<const SubRegion *, NonLoc>> &RawOffset =
570 auto[Reg, ByteOffset] = *RawOffset;
574StateUpdateReporter SUR(Reg, ByteOffset,
E,
C);
578 if(!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) {
589 if(PrecedesLowerBound) {
591 if(!WithinLowerBound) {
594reportOOB(
C, PrecedesLowerBound, Msgs, ByteOffset, std::nullopt);
599SUR.recordNonNegativeAssumption();
605 if(WithinLowerBound)
606State = WithinLowerBound;
611 if(
autoKnownSize =
Size.getAs<
NonLoc>()) {
617 boolAlsoMentionUnderflow = SUR.assumedNonNegative();
619 auto[WithinUpperBound, ExceedsUpperBound] =
622 if(ExceedsUpperBound) {
624 if(!WithinUpperBound) {
628 if(isIdiomaticPastTheEndPtr(
E, ExceedsUpperBound, ByteOffset,
630 C.addTransition(ExceedsUpperBound, SUR.createNoteTag(
C));
636Location, AlsoMentionUnderflow);
637reportOOB(
C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
647 const char*OffsetName =
"offset";
648 if(
const auto*ASE = dyn_cast<ArraySubscriptExpr>(
E))
649 if(
isTainted(State, ASE->getIdx(),
C.getLocationContext()))
650OffsetName =
"index";
652Messages Msgs =
getTaintMsgs(Reg, OffsetName, AlsoMentionUnderflow);
653reportOOB(
C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize,
659SUR.recordUpperBoundAssumption(*KnownSize);
665 if(WithinUpperBound)
666State = WithinUpperBound;
670 C.addTransition(State, SUR.createNoteTag(
C));
675 NonLocVal,
boolMarkTaint) {
698 NonLocOffset, std::optional<NonLoc> Extent,
699 boolIsTaintBug
)
const{
705 autoBR = std::make_unique<PathSensitiveBugReport>(
706IsTaintBug ? TaintBT : BT, Msgs.Short, Msgs.Full, ErrorNode);
721markPartsInteresting(*BR, ErrorState, Offset, IsTaintBug);
723markPartsInteresting(*BR, ErrorState, *Extent, IsTaintBug);
725 C.emitReport(std::move(BR));
728boolArrayBoundCheckerV2::isFromCtypeMacro(
const Stmt*S,
ASTContext&ACtx) {
730 if(!
Loc.isMacroID())
736 if(MacroName.size() < 7 || MacroName[0] !=
'i'|| MacroName[1] !=
's')
739 return((MacroName ==
"isalnum") || (MacroName ==
"isalpha") ||
740(MacroName ==
"isblank") || (MacroName ==
"isdigit") ||
741(MacroName ==
"isgraph") || (MacroName ==
"islower") ||
742(MacroName ==
"isnctrl") || (MacroName ==
"isprint") ||
743(MacroName ==
"ispunct") || (MacroName ==
"isspace") ||
744(MacroName ==
"isupper") || (MacroName ==
"isxdigit"));
747boolArrayBoundCheckerV2::isInAddressOf(
const Stmt*S,
ASTContext&ACtx) {
751 if(Parents.
empty())
753S = Parents[0].get<
Stmt>();
754}
while(isa_and_nonnull<ParenExpr, ImplicitCastExpr>(S));
755 const auto*UnaryOp = dyn_cast_or_null<UnaryOperator>(S);
756 returnUnaryOp && UnaryOp->getOpcode() == UO_AddrOf;
759boolArrayBoundCheckerV2::isIdiomaticPastTheEndPtr(
const Expr*
E,
763 if(isa<ArraySubscriptExpr>(
E) && isInAddressOf(
E,
C.getASTContext())) {
765State, Offset, Limit,
C.getSValBuilder(),
true);
766 returnEqualsToThreshold && !NotEqualToThreshold;
775boolento::shouldRegisterArrayBoundCheckerV2(
const CheckerManager&mgr) {
static std::pair< ProgramStateRef, ProgramStateRef > compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold, SValBuilder &SVB, bool CheckEquality=false)
static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region, NonLoc Offset, NonLoc Extent, SVal Location, bool AlsoMentionUnderflow)
static std::optional< std::pair< const SubRegion *, NonLoc > > computeOffset(ProgramStateRef State, SValBuilder &SVB, SVal Location)
For a given Location that can be represented as a symbolic expression Arr[Idx] (or perhaps Arr[Idx1][...
static Messages getTaintMsgs(const SubRegion *Region, const char *OffsetName, bool AlsoMentionUnderflow)
static bool isNegative(SValBuilder &SVB, ProgramStateRef State, NonLoc Value)
static std::string getRegionName(const SubRegion *Region)
static std::optional< int64_t > getConcreteValue(NonLoc SV)
static Messages getPrecedesMsgs(const SubRegion *Region, NonLoc Offset)
static bool isUnsigned(SValBuilder &SVB, NonLoc Value)
static std::pair< NonLoc, nonloc::ConcreteInt > getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent, SValBuilder &svalBuilder)
static bool tryDividePair(std::optional< int64_t > &Val1, std::optional< int64_t > &Val2, int64_t Divisor)
Try to divide Val1 and Val2 (in place) by Divisor and return true if it can be performed (Divisor is ...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
ParentMapContext & getParentMapContext()
Returns the dynamic AST node parent map context.
const LangOptions & getLangOpts() const
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
This represents one expression.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
DynTypedNodeList getParents(const NodeT &Node)
Returns the parents of the given node (within the traversal scope).
A (possibly-)qualified type.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Encodes a location in the source.
Stmt - This represents one statement.
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
A record of the "type" of an APSInt, used for conversions.
llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY
Convert and return a new APSInt with the given value, but this type's bit width and signedness.
Template implementation for all binary symbolic expressions.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
ElementRegion is used to represent both array elements and casts.
QualType getElementType() const
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
std::string getDescriptiveName(bool UseQuotes=true) const
Get descriptive name for memory region.
const RegionTy * getAs() const
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
The tag upon which the TagVisitor reacts.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
bool isInteresting(SymbolRef sym) const
NonLoc makeArrayIndex(uint64_t idx)
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getArrayIndexType() const
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.
QualType getConditionType() const
virtual const llvm::APSInt * getMaxValue(ProgramStateRef state, SVal val)=0
Tries to get the maximal possible (integer) value of a given SVal.
NonLoc makeZeroArrayIndex()
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
llvm::iterator_range< symbol_iterator > symbols() const
Value representing integer constant.
APSIntPtr getValue() const
Represents symbolic expression that isn't a location.
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
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.
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4