1 //=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This defines VLASizeChecker, a builtin check in ExprEngine that 10 // performs checks for declaration of VLA of undefined or zero size. 11 // In addition, VLASizeChecker is responsible for defining the extent 12 // of the MemRegion that represents a VLA. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 17 #include "clang/AST/CharUnits.h" 18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 19 #include "clang/StaticAnalyzer/Core/Checker.h" 20 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22 #include "llvm/ADT/STLExtras.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 using namespace clang; 27 using namespace ento; 28 29 namespace { 30 class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { 31 mutable std::unique_ptr<BugType> BT; 32 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative }; 33 34 void reportBug(VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, 35 CheckerContext &C, 36 std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const; 37 38 public: 39 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 40 }; 41 } // end anonymous namespace 42 43 void VLASizeChecker::reportBug( 44 VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, 45 CheckerContext &C, std::unique_ptr<BugReporterVisitor> Visitor) const { 46 // Generate an error node. 47 ExplodedNode *N = C.generateErrorNode(State); 48 if (!N) 49 return; 50 51 if (!BT) 52 BT.reset(new BuiltinBug( 53 this, "Dangerous variable-length array (VLA) declaration")); 54 55 SmallString<256> buf; 56 llvm::raw_svector_ostream os(buf); 57 os << "Declared variable-length array (VLA) "; 58 switch (Kind) { 59 case VLA_Garbage: 60 os << "uses a garbage value as its size"; 61 break; 62 case VLA_Zero: 63 os << "has zero size"; 64 break; 65 case VLA_Tainted: 66 os << "has tainted size"; 67 break; 68 case VLA_Negative: 69 os << "has negative size"; 70 break; 71 } 72 73 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N); 74 report->addVisitor(std::move(Visitor)); 75 report->addRange(SizeE->getSourceRange()); 76 bugreporter::trackExpressionValue(N, SizeE, *report); 77 C.emitReport(std::move(report)); 78 } 79 80 void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 81 if (!DS->isSingleDecl()) 82 return; 83 84 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 85 if (!VD) 86 return; 87 88 ASTContext &Ctx = C.getASTContext(); 89 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 90 if (!VLA) 91 return; 92 93 // FIXME: Handle multi-dimensional VLAs. 94 const Expr *SE = VLA->getSizeExpr(); 95 ProgramStateRef state = C.getState(); 96 SVal sizeV = C.getSVal(SE); 97 98 if (sizeV.isUndef()) { 99 reportBug(VLA_Garbage, SE, state, C); 100 return; 101 } 102 103 // See if the size value is known. It can't be undefined because we would have 104 // warned about that already. 105 if (sizeV.isUnknown()) 106 return; 107 108 // Check if the size is tainted. 109 if (state->isTainted(sizeV)) { 110 reportBug(VLA_Tainted, SE, nullptr, C, 111 llvm::make_unique<TaintBugVisitor>(sizeV)); 112 return; 113 } 114 115 // Check if the size is zero. 116 DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); 117 118 ProgramStateRef stateNotZero, stateZero; 119 std::tie(stateNotZero, stateZero) = state->assume(sizeD); 120 121 if (stateZero && !stateNotZero) { 122 reportBug(VLA_Zero, SE, stateZero, C); 123 return; 124 } 125 126 // From this point on, assume that the size is not zero. 127 state = stateNotZero; 128 129 // VLASizeChecker is responsible for defining the extent of the array being 130 // declared. We do this by multiplying the array length by the element size, 131 // then matching that with the array region's extent symbol. 132 133 // Check if the size is negative. 134 SValBuilder &svalBuilder = C.getSValBuilder(); 135 136 QualType Ty = SE->getType(); 137 DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty); 138 139 SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty); 140 if (Optional<DefinedSVal> LessThanZeroDVal = 141 LessThanZeroVal.getAs<DefinedSVal>()) { 142 ConstraintManager &CM = C.getConstraintManager(); 143 ProgramStateRef StatePos, StateNeg; 144 145 std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal); 146 if (StateNeg && !StatePos) { 147 reportBug(VLA_Negative, SE, state, C); 148 return; 149 } 150 state = StatePos; 151 } 152 153 // Convert the array length to size_t. 154 QualType SizeTy = Ctx.getSizeType(); 155 NonLoc ArrayLength = 156 svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>(); 157 158 // Get the element size. 159 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 160 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 161 162 // Multiply the array length by the element size. 163 SVal ArraySizeVal = svalBuilder.evalBinOpNN( 164 state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy); 165 166 // Finally, assume that the array's extent matches the given size. 167 const LocationContext *LC = C.getLocationContext(); 168 DefinedOrUnknownSVal Extent = 169 state->getRegion(VD, LC)->getExtent(svalBuilder); 170 DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>(); 171 DefinedOrUnknownSVal sizeIsKnown = 172 svalBuilder.evalEQ(state, Extent, ArraySize); 173 state = state->assume(sizeIsKnown, true); 174 175 // Assume should not fail at this point. 176 assert(state); 177 178 // Remember our assumptions! 179 C.addTransition(state); 180 } 181 182 void ento::registerVLASizeChecker(CheckerManager &mgr) { 183 mgr.registerChecker<VLASizeChecker>(); 184 } 185