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/AST/CharUnits.h" 17 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 18 #include "clang/StaticAnalyzer/Checkers/Taint.h" 19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20 #include "clang/StaticAnalyzer/Core/Checker.h" 21 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 24 #include "llvm/ADT/STLExtras.h" 25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <optional> 28 29 using namespace clang; 30 using namespace ento; 31 using namespace taint; 32 33 namespace { 34 class VLASizeChecker 35 : public Checker<check::PreStmt<DeclStmt>, 36 check::PreStmt<UnaryExprOrTypeTraitExpr>> { 37 mutable std::unique_ptr<BugType> BT; 38 enum VLASize_Kind { 39 VLA_Garbage, 40 VLA_Zero, 41 VLA_Tainted, 42 VLA_Negative, 43 VLA_Overflow 44 }; 45 46 /// Check a VLA for validity. 47 /// Every dimension of the array and the total size is checked for validity. 48 /// Returns null or a new state where the size is validated. 49 /// 'ArraySize' will contain SVal that refers to the total size (in char) 50 /// of the array. 51 ProgramStateRef checkVLA(CheckerContext &C, ProgramStateRef State, 52 const VariableArrayType *VLA, SVal &ArraySize) const; 53 /// Check a single VLA index size expression for validity. 54 ProgramStateRef checkVLAIndexSize(CheckerContext &C, ProgramStateRef State, 55 const Expr *SizeE) const; 56 57 void reportBug(VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, 58 CheckerContext &C, 59 std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const; 60 61 public: 62 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 63 void checkPreStmt(const UnaryExprOrTypeTraitExpr *UETTE, 64 CheckerContext &C) const; 65 }; 66 } // end anonymous namespace 67 68 ProgramStateRef VLASizeChecker::checkVLA(CheckerContext &C, 69 ProgramStateRef State, 70 const VariableArrayType *VLA, 71 SVal &ArraySize) const { 72 assert(VLA && "Function should be called with non-null VLA argument."); 73 74 const VariableArrayType *VLALast = nullptr; 75 llvm::SmallVector<const Expr *, 2> VLASizes; 76 77 // Walk over the VLAs for every dimension until a non-VLA is found. 78 // There is a VariableArrayType for every dimension (fixed or variable) until 79 // the most inner array that is variably modified. 80 // Dimension sizes are collected into 'VLASizes'. 'VLALast' is set to the 81 // innermost VLA that was encountered. 82 // In "int vla[x][2][y][3]" this will be the array for index "y" (with type 83 // int[3]). 'VLASizes' contains 'x', '2', and 'y'. 84 while (VLA) { 85 const Expr *SizeE = VLA->getSizeExpr(); 86 State = checkVLAIndexSize(C, State, SizeE); 87 if (!State) 88 return nullptr; 89 VLASizes.push_back(SizeE); 90 VLALast = VLA; 91 VLA = C.getASTContext().getAsVariableArrayType(VLA->getElementType()); 92 }; 93 assert(VLALast && 94 "Array should have at least one variably-modified dimension."); 95 96 ASTContext &Ctx = C.getASTContext(); 97 SValBuilder &SVB = C.getSValBuilder(); 98 CanQualType SizeTy = Ctx.getSizeType(); 99 uint64_t SizeMax = 100 SVB.getBasicValueFactory().getMaxValue(SizeTy).getZExtValue(); 101 102 // Get the element size. 103 CharUnits EleSize = Ctx.getTypeSizeInChars(VLALast->getElementType()); 104 NonLoc ArrSize = 105 SVB.makeIntVal(EleSize.getQuantity(), SizeTy).castAs<NonLoc>(); 106 107 // Try to calculate the known real size of the array in KnownSize. 108 uint64_t KnownSize = 0; 109 if (const llvm::APSInt *KV = SVB.getKnownValue(State, ArrSize)) 110 KnownSize = KV->getZExtValue(); 111 112 for (const Expr *SizeE : VLASizes) { 113 auto SizeD = C.getSVal(SizeE).castAs<DefinedSVal>(); 114 // Convert the array length to size_t. 115 NonLoc IndexLength = 116 SVB.evalCast(SizeD, SizeTy, SizeE->getType()).castAs<NonLoc>(); 117 // Multiply the array length by the element size. 118 SVal Mul = SVB.evalBinOpNN(State, BO_Mul, ArrSize, IndexLength, SizeTy); 119 if (auto MulNonLoc = Mul.getAs<NonLoc>()) 120 ArrSize = *MulNonLoc; 121 else 122 // Extent could not be determined. 123 return State; 124 125 if (const llvm::APSInt *IndexLVal = SVB.getKnownValue(State, IndexLength)) { 126 // Check if the array size will overflow. 127 // Size overflow check does not work with symbolic expressions because a 128 // overflow situation can not be detected easily. 129 uint64_t IndexL = IndexLVal->getZExtValue(); 130 // FIXME: See https://reviews.llvm.org/D80903 for discussion of 131 // some difference in assume and getKnownValue that leads to 132 // unexpected behavior. Just bail on IndexL == 0 at this point. 133 if (IndexL == 0) 134 return nullptr; 135 136 if (KnownSize <= SizeMax / IndexL) { 137 KnownSize *= IndexL; 138 } else { 139 // Array size does not fit into size_t. 140 reportBug(VLA_Overflow, SizeE, State, C); 141 return nullptr; 142 } 143 } else { 144 KnownSize = 0; 145 } 146 } 147 148 ArraySize = ArrSize; 149 150 return State; 151 } 152 153 ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C, 154 ProgramStateRef State, 155 const Expr *SizeE) const { 156 SVal SizeV = C.getSVal(SizeE); 157 158 if (SizeV.isUndef()) { 159 reportBug(VLA_Garbage, SizeE, State, C); 160 return nullptr; 161 } 162 163 // See if the size value is known. It can't be undefined because we would have 164 // warned about that already. 165 if (SizeV.isUnknown()) 166 return nullptr; 167 168 // Check if the size is tainted. 169 if (isTainted(State, SizeV)) { 170 reportBug(VLA_Tainted, SizeE, nullptr, C, 171 std::make_unique<TaintBugVisitor>(SizeV)); 172 return nullptr; 173 } 174 175 // Check if the size is zero. 176 DefinedSVal SizeD = SizeV.castAs<DefinedSVal>(); 177 178 ProgramStateRef StateNotZero, StateZero; 179 std::tie(StateNotZero, StateZero) = State->assume(SizeD); 180 181 if (StateZero && !StateNotZero) { 182 reportBug(VLA_Zero, SizeE, StateZero, C); 183 return nullptr; 184 } 185 186 // From this point on, assume that the size is not zero. 187 State = StateNotZero; 188 189 // Check if the size is negative. 190 SValBuilder &SVB = C.getSValBuilder(); 191 192 QualType SizeTy = SizeE->getType(); 193 DefinedOrUnknownSVal Zero = SVB.makeZeroVal(SizeTy); 194 195 SVal LessThanZeroVal = SVB.evalBinOp(State, BO_LT, SizeD, Zero, SizeTy); 196 if (std::optional<DefinedSVal> LessThanZeroDVal = 197 LessThanZeroVal.getAs<DefinedSVal>()) { 198 ConstraintManager &CM = C.getConstraintManager(); 199 ProgramStateRef StatePos, StateNeg; 200 201 std::tie(StateNeg, StatePos) = CM.assumeDual(State, *LessThanZeroDVal); 202 if (StateNeg && !StatePos) { 203 reportBug(VLA_Negative, SizeE, State, C); 204 return nullptr; 205 } 206 State = StatePos; 207 } 208 209 return State; 210 } 211 212 void VLASizeChecker::reportBug( 213 VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, 214 CheckerContext &C, std::unique_ptr<BugReporterVisitor> Visitor) const { 215 // Generate an error node. 216 ExplodedNode *N = C.generateErrorNode(State); 217 if (!N) 218 return; 219 220 if (!BT) 221 BT.reset(new BuiltinBug( 222 this, "Dangerous variable-length array (VLA) declaration")); 223 224 SmallString<256> buf; 225 llvm::raw_svector_ostream os(buf); 226 os << "Declared variable-length array (VLA) "; 227 switch (Kind) { 228 case VLA_Garbage: 229 os << "uses a garbage value as its size"; 230 break; 231 case VLA_Zero: 232 os << "has zero size"; 233 break; 234 case VLA_Tainted: 235 os << "has tainted size"; 236 break; 237 case VLA_Negative: 238 os << "has negative size"; 239 break; 240 case VLA_Overflow: 241 os << "has too large size"; 242 break; 243 } 244 245 auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N); 246 report->addVisitor(std::move(Visitor)); 247 report->addRange(SizeE->getSourceRange()); 248 bugreporter::trackExpressionValue(N, SizeE, *report); 249 C.emitReport(std::move(report)); 250 } 251 252 void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 253 if (!DS->isSingleDecl()) 254 return; 255 256 ASTContext &Ctx = C.getASTContext(); 257 SValBuilder &SVB = C.getSValBuilder(); 258 ProgramStateRef State = C.getState(); 259 QualType TypeToCheck; 260 261 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 262 263 if (VD) 264 TypeToCheck = VD->getType().getCanonicalType(); 265 else if (const auto *TND = dyn_cast<TypedefNameDecl>(DS->getSingleDecl())) 266 TypeToCheck = TND->getUnderlyingType().getCanonicalType(); 267 else 268 return; 269 270 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(TypeToCheck); 271 if (!VLA) 272 return; 273 274 // Check the VLA sizes for validity. 275 276 SVal ArraySize; 277 278 State = checkVLA(C, State, VLA, ArraySize); 279 if (!State) 280 return; 281 282 if (!isa<NonLoc>(ArraySize)) { 283 // Array size could not be determined but state may contain new assumptions. 284 C.addTransition(State); 285 return; 286 } 287 288 // VLASizeChecker is responsible for defining the extent of the array. 289 if (VD) { 290 State = 291 setDynamicExtent(State, State->getRegion(VD, C.getLocationContext()), 292 ArraySize.castAs<NonLoc>(), SVB); 293 } 294 295 // Remember our assumptions! 296 C.addTransition(State); 297 } 298 299 void VLASizeChecker::checkPreStmt(const UnaryExprOrTypeTraitExpr *UETTE, 300 CheckerContext &C) const { 301 // Want to check for sizeof. 302 if (UETTE->getKind() != UETT_SizeOf) 303 return; 304 305 // Ensure a type argument. 306 if (!UETTE->isArgumentType()) 307 return; 308 309 const VariableArrayType *VLA = C.getASTContext().getAsVariableArrayType( 310 UETTE->getTypeOfArgument().getCanonicalType()); 311 // Ensure that the type is a VLA. 312 if (!VLA) 313 return; 314 315 ProgramStateRef State = C.getState(); 316 SVal ArraySize; 317 State = checkVLA(C, State, VLA, ArraySize); 318 if (!State) 319 return; 320 321 C.addTransition(State); 322 } 323 324 void ento::registerVLASizeChecker(CheckerManager &mgr) { 325 mgr.registerChecker<VLASizeChecker>(); 326 } 327 328 bool ento::shouldRegisterVLASizeChecker(const CheckerManager &mgr) { 329 return true; 330 } 331