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