24#include "llvm/Support/raw_ostream.h"
33 :
public Checker<check::PreStmt<DeclStmt>,
34 check::PreStmt<UnaryExprOrTypeTraitExpr>> {
35 const BugType BT{
this,
"Dangerous variable-length array (VLA) declaration"};
36 const BugType TaintBT{
this,
37 "Dangerous variable-length array (VLA) declaration",
39 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Negative, VLA_Overflow };
47 const VariableArrayType *VLA, SVal &ArraySize)
const;
50 const Expr *SizeE)
const;
52 void reportBug(VLASize_Kind Kind,
const Expr *SizeE,
ProgramStateRef State,
53 CheckerContext &
C)
const;
56 CheckerContext &
C, SVal TaintedSVal)
const;
59 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
60 void checkPreStmt(
const UnaryExprOrTypeTraitExpr *UETTE,
61 CheckerContext &
C)
const;
68 SVal &ArraySize)
const {
69 assert(VLA &&
"Function should be called with non-null VLA argument.");
71 const VariableArrayType *VLALast =
nullptr;
72 llvm::SmallVector<const Expr *, 2> VLASizes;
83 State = checkVLAIndexSize(
C, State, SizeE);
86 VLASizes.push_back(SizeE);
91 "Array should have at least one variably-modified dimension.");
93 ASTContext &Ctx =
C.getASTContext();
94 SValBuilder &SVB =
C.getSValBuilder();
106 if (
const llvm::APSInt *KV = SVB.
getKnownValue(State, ArrSize))
107 KnownSize = KV->getZExtValue();
109 for (
const Expr *SizeE : VLASizes) {
110 auto SizeD =
C.getSVal(SizeE).castAs<DefinedSVal>();
115 SVal
Mul = SVB.
evalBinOpNN(State, BO_Mul, ArrSize, IndexLength, SizeTy);
116 if (
auto MulNonLoc =
Mul.getAs<NonLoc>())
117 ArrSize = *MulNonLoc;
122 if (
const llvm::APSInt *IndexLVal = SVB.
getKnownValue(State, IndexLength)) {
126 uint64_t IndexL = IndexLVal->getZExtValue();
133 if (KnownSize <= SizeMax / IndexL) {
137 reportBug(VLA_Overflow, SizeE, State,
C);
152 const Expr *SizeE)
const {
153 SVal SizeV =
C.getSVal(SizeE);
156 reportBug(VLA_Garbage, SizeE, State,
C);
166 DefinedSVal SizeD = SizeV.
castAs<DefinedSVal>();
169 std::tie(StateNotZero, StateZero) = State->assume(SizeD);
171 if (StateZero && !StateNotZero) {
172 reportBug(VLA_Zero, SizeE, StateZero,
C);
177 State = StateNotZero;
180 SValBuilder &SVB =
C.getSValBuilder();
182 QualType SizeTy = SizeE->
getType();
185 SVal LessThanZeroVal =
188 if (std::optional<DefinedSVal> LessThanZeroDVal =
189 LessThanZeroVal.
getAs<DefinedSVal>()) {
190 ConstraintManager &CM =
C.getConstraintManager();
192 std::tie(StateNeg, StatePos) = CM.
assumeDual(State, *LessThanZeroDVal);
193 if (StateNeg && !StatePos) {
194 reportBug(VLA_Negative, SizeE, State,
C);
201 if ((StateNeg || StateZero) &&
isTainted(State, SizeV)) {
202 reportTaintBug(SizeE, State,
C, SizeV);
209void VLASizeChecker::reportTaintBug(
const Expr *SizeE,
ProgramStateRef State,
210 CheckerContext &
C, SVal TaintedSVal)
const {
212 ExplodedNode *N =
C.generateErrorNode(State);
216 SmallString<256> buf;
217 llvm::raw_svector_ostream os(buf);
218 os <<
"Declared variable-length array (VLA) ";
219 os <<
"has tainted (attacker controlled) size that can be 0 or negative";
221 auto report = std::make_unique<PathSensitiveBugReport>(TaintBT, os.str(), N);
227 report->markInteresting(Sym);
228 C.emitReport(std::move(report));
231void VLASizeChecker::reportBug(VLASize_Kind Kind,
const Expr *SizeE,
234 ExplodedNode *N =
C.generateErrorNode(State);
238 SmallString<256> buf;
239 llvm::raw_svector_ostream os(buf);
240 os <<
"Declared variable-length array (VLA) ";
243 os <<
"uses a garbage value as its size";
246 os <<
"has zero size";
249 os <<
"has negative size";
252 os <<
"has too large size";
256 auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
259 C.emitReport(std::move(report));
262void VLASizeChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
266 ASTContext &Ctx =
C.getASTContext();
268 QualType TypeToCheck;
274 else if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl()))
275 TypeToCheck = TND->getUnderlyingType().getCanonicalType();
287 State = checkVLA(
C, State, VLA, ArraySize);
293 C.addTransition(State);
301 ArraySize.
castAs<NonLoc>());
305 C.addTransition(State);
308void VLASizeChecker::checkPreStmt(
const UnaryExprOrTypeTraitExpr *UETTE,
309 CheckerContext &
C)
const {
311 if (UETTE->
getKind() != UETT_SizeOf)
318 const VariableArrayType *VLA =
C.getASTContext().getAsVariableArrayType(
326 State = checkVLA(
C, State, VLA, ArraySize);
330 C.addTransition(State);
333void ento::registerVLASizeChecker(CheckerManager &mgr) {
337bool 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
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.
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)