VLASizeChecker.cpp revision 9b663716449b618ba0390b1dbebc54fa8e971124
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 "InternalChecks.h" 18#include "clang/AST/CharUnits.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 22 23using namespace clang; 24using namespace ento; 25 26namespace { 27class VLASizeChecker : public CheckerVisitor<VLASizeChecker> { 28 BugType *BT_zero; 29 BugType *BT_undef; 30 31public: 32 VLASizeChecker() : BT_zero(0), BT_undef(0) {} 33 static void *getTag() { static int tag = 0; return &tag; } 34 void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS); 35}; 36} // end anonymous namespace 37 38void ento::RegisterVLASizeChecker(ExprEngine &Eng) { 39 Eng.registerCheck(new VLASizeChecker()); 40} 41 42void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { 43 if (!DS->isSingleDecl()) 44 return; 45 46 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 47 if (!VD) 48 return; 49 50 ASTContext &Ctx = C.getASTContext(); 51 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 52 if (!VLA) 53 return; 54 55 // FIXME: Handle multi-dimensional VLAs. 56 const Expr* SE = VLA->getSizeExpr(); 57 const GRState *state = C.getState(); 58 SVal sizeV = state->getSVal(SE); 59 60 if (sizeV.isUndef()) { 61 // Generate an error node. 62 ExplodedNode *N = C.generateSink(); 63 if (!N) 64 return; 65 66 if (!BT_undef) 67 BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a " 68 "garbage value as its size"); 69 70 EnhancedBugReport *report = 71 new EnhancedBugReport(*BT_undef, BT_undef->getName(), N); 72 report->addRange(SE->getSourceRange()); 73 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); 74 C.EmitReport(report); 75 return; 76 } 77 78 // See if the size value is known. It can't be undefined because we would have 79 // warned about that already. 80 if (sizeV.isUnknown()) 81 return; 82 83 // Check if the size is zero. 84 DefinedSVal sizeD = cast<DefinedSVal>(sizeV); 85 86 const GRState *stateNotZero, *stateZero; 87 llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); 88 89 if (stateZero && !stateNotZero) { 90 ExplodedNode* N = C.generateSink(stateZero); 91 if (!BT_zero) 92 BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero " 93 "size"); 94 95 EnhancedBugReport *report = 96 new EnhancedBugReport(*BT_zero, BT_zero->getName(), N); 97 report->addRange(SE->getSourceRange()); 98 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); 99 C.EmitReport(report); 100 return; 101 } 102 103 // From this point on, assume that the size is not zero. 104 state = stateNotZero; 105 106 // VLASizeChecker is responsible for defining the extent of the array being 107 // declared. We do this by multiplying the array length by the element size, 108 // then matching that with the array region's extent symbol. 109 110 // Convert the array length to size_t. 111 SValBuilder &svalBuilder = C.getSValBuilder(); 112 QualType SizeTy = Ctx.getSizeType(); 113 NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy, 114 SE->getType())); 115 116 // Get the element size. 117 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 118 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 119 120 // Multiply the array length by the element size. 121 SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength, 122 cast<NonLoc>(EleSizeVal), SizeTy); 123 124 // Finally, assume that the array's extent matches the given size. 125 const LocationContext *LC = C.getPredecessor()->getLocationContext(); 126 DefinedOrUnknownSVal Extent = 127 state->getRegion(VD, LC)->getExtent(svalBuilder); 128 DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal); 129 DefinedOrUnknownSVal sizeIsKnown = 130 svalBuilder.evalEQ(state, Extent, ArraySize); 131 state = state->assume(sizeIsKnown, true); 132 133 // Assume should not fail at this point. 134 assert(state); 135 136 // Remember our assumptions! 137 C.addTransition(state); 138} 139