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