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