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