32 :
public Checker<check::PreStmt<DeclStmt>,
33 check::PreStmt<UnaryExprOrTypeTraitExpr>> {
34 const BugType BT{
this,
"Dangerous variable-length array (VLA) declaration"};
35 const BugType TaintBT{
this,
36 "Dangerous variable-length array (VLA) declaration",
38 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Negative, VLA_Overflow };
46 const VariableArrayType *VLA, SVal &ArraySize)
const;
49 const Expr *SizeE)
const;
51 void reportBug(VLASize_Kind Kind,
const Expr *SizeE,
ProgramStateRef State,
52 CheckerContext &
C)
const;
55 CheckerContext &
C, SVal TaintedSVal)
const;
58 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
59 void checkPreStmt(
const UnaryExprOrTypeTraitExpr *UETTE,
60 CheckerContext &
C)
const;
67 SVal &ArraySize)
const {
68 assert(VLA &&
"Function should be called with non-null VLA argument.");
70 const VariableArrayType *VLALast =
nullptr;
71 llvm::SmallVector<const Expr *, 2> VLASizes;
82 State = checkVLAIndexSize(
C, State, SizeE);
85 VLASizes.push_back(SizeE);
90 "Array should have at least one variably-modified dimension.");
92 ASTContext &Ctx =
C.getASTContext();
93 SValBuilder &SVB =
C.getSValBuilder();
105 if (
const llvm::APSInt *KV = SVB.
getKnownValue(State, ArrSize))
106 KnownSize = KV->getZExtValue();
108 for (
const Expr *SizeE : VLASizes) {
109 auto SizeD =
C.getSVal(SizeE).castAs<DefinedSVal>();
114 SVal
Mul = SVB.
evalBinOpNN(State, BO_Mul, ArrSize, IndexLength, SizeTy);
115 if (
auto MulNonLoc =
Mul.getAs<NonLoc>())
116 ArrSize = *MulNonLoc;
121 if (
const llvm::APSInt *IndexLVal = SVB.
getKnownValue(State, IndexLength)) {
125 uint64_t IndexL = IndexLVal->getZExtValue();
132 if (KnownSize <= SizeMax / IndexL) {
136 reportBug(VLA_Overflow, SizeE, State,
C);
151 const Expr *SizeE)
const {
152 SVal SizeV =
C.getSVal(SizeE);
155 reportBug(VLA_Garbage, SizeE, State,
C);
165 DefinedSVal SizeD = SizeV.
castAs<DefinedSVal>();
168 std::tie(StateNotZero, StateZero) = State->assume(SizeD);
170 if (StateZero && !StateNotZero) {
171 reportBug(VLA_Zero, SizeE, StateZero,
C);
176 State = StateNotZero;
179 SValBuilder &SVB =
C.getSValBuilder();
181 QualType SizeTy = SizeE->
getType();
184 SVal LessThanZeroVal =
187 if (std::optional<DefinedSVal> LessThanZeroDVal =
188 LessThanZeroVal.
getAs<DefinedSVal>()) {
189 ConstraintManager &CM =
C.getConstraintManager();
191 std::tie(StateNeg, StatePos) = CM.
assumeDual(State, *LessThanZeroDVal);
192 if (StateNeg && !StatePos) {
193 reportBug(VLA_Negative, SizeE, State,
C);
200 if ((StateNeg || StateZero) &&
isTainted(State, SizeV)) {
201 reportTaintBug(SizeE, State,
C, SizeV);
208void VLASizeChecker::reportTaintBug(
const Expr *SizeE,
ProgramStateRef State,
209 CheckerContext &
C, SVal TaintedSVal)
const {
211 ExplodedNode *N =
C.generateErrorNode(State);
215 auto report = std::make_unique<PathSensitiveBugReport>(
217 "Declared variable-length array (VLA) has tainted (attacker controlled) "
218 "size that can be 0 or negative",
225 report->markInteresting(Sym);
226 C.emitReport(std::move(report));
229void VLASizeChecker::reportBug(VLASize_Kind Kind,
const Expr *SizeE,
232 ExplodedNode *N =
C.generateErrorNode(State);
236 SmallString<256> buf;
237 llvm::raw_svector_ostream os(buf);
238 os <<
"Declared variable-length array (VLA) ";
241 os <<
"uses a garbage value as its size";
244 os <<
"has zero size";
247 os <<
"has negative size";
250 os <<
"has too large size";
254 auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
257 C.emitReport(std::move(report));
260void VLASizeChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
264 ASTContext &Ctx =
C.getASTContext();
266 QualType TypeToCheck;
272 else if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl()))
273 TypeToCheck = TND->getUnderlyingType().getCanonicalType();
285 State = checkVLA(
C, State, VLA, ArraySize);
291 C.addTransition(State);
298 ArraySize.
castAs<NonLoc>());
302 C.addTransition(State);
305void VLASizeChecker::checkPreStmt(
const UnaryExprOrTypeTraitExpr *UETTE,
306 CheckerContext &
C)
const {
308 if (UETTE->
getKind() != UETT_SizeOf)
315 const VariableArrayType *VLA =
C.getASTContext().getAsVariableArrayType(
323 State = checkVLA(
C, State, VLA, ArraySize);
327 C.addTransition(State);
330void ento::registerVLASizeChecker(CheckerManager &mgr) {
334bool ento::shouldRegisterVLASizeChecker(
const CheckerManager &mgr) {
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const VariableArrayType * getAsVariableArrayType(QualType T) const
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QualType getElementType() const
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
QualType getCanonicalType() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
QualType getTypeOfArgument() const
Gets the argument type, or the type of the argument expression, whichever is appropriate.
bool isArgumentType() const
UnaryExprOrTypeTrait getKind() const
Represents a C array with a specified size that is not an integer-constant-expression.
Expr * getSizeExpr() const
APSIntPtr getMaxValue(const llvm::APSInt &v)
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
Returns a pair of states (StTrue, StFalse) where the given condition is assumed to be true or false,...
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
virtual const llvm::APSInt * getKnownValue(ProgramStateRef state, SVal val)=0
Evaluates a given SVal.
BasicValueFactory & getBasicValueFactory()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
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.
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
QualType getConditionType() const
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const TaintedData
bool isTainted(ProgramStateRef State, const Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Check if the expression has a tainted value in the given state.
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Expr *E, const StackFrame *SF, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given expression and state.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
bool Mul(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)