1174641Skmacy//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===// 2237263Snp// 3174641Skmacy// The LLVM Compiler Infrastructure 4174641Skmacy// 5174641Skmacy// This file is distributed under the University of Illinois Open Source 6174641Skmacy// License. See LICENSE.TXT for details. 7174641Skmacy// 8174641Skmacy//===----------------------------------------------------------------------===// 9174641Skmacy// 10174641Skmacy// This defines VLASizeChecker, a builtin check in ExprEngine that 11174641Skmacy// performs checks for declaration of VLA of undefined or zero size. 12174641Skmacy// In addition, VLASizeChecker is responsible for defining the extent 13174641Skmacy// of the MemRegion that represents a VLA. 14174641Skmacy// 15174641Skmacy//===----------------------------------------------------------------------===// 16174641Skmacy 17174641Skmacy#include "ClangSACheckers.h" 18174641Skmacy#include "clang/AST/CharUnits.h" 19174641Skmacy#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20174641Skmacy#include "clang/StaticAnalyzer/Core/Checker.h" 21174641Skmacy#include "clang/StaticAnalyzer/Core/CheckerManager.h" 22174641Skmacy#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23174641Skmacy#include "llvm/ADT/STLExtras.h" 24174641Skmacy#include "llvm/ADT/SmallString.h" 25174641Skmacy#include "llvm/Support/raw_ostream.h" 26174641Skmacy 27174641Skmacyusing namespace clang; 28174641Skmacyusing namespace ento; 29174641Skmacy 30174641Skmacynamespace { 31174641Skmacyclass VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { 32176472Skmacy mutable OwningPtr<BugType> BT; 33183292Skmacy enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted }; 34174641Skmacy 35237263Snp void reportBug(VLASize_Kind Kind, 36237263Snp const Expr *SizeE, 37237263Snp ProgramStateRef State, 38237263Snp CheckerContext &C) const; 39237263Snppublic: 40237263Snp void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 41237263Snp}; 42237263Snp} // end anonymous namespace 43237263Snp 44237263Snpvoid VLASizeChecker::reportBug(VLASize_Kind Kind, 45237263Snp const Expr *SizeE, 46237263Snp ProgramStateRef State, 47239544Snp CheckerContext &C) const { 48237263Snp // Generate an error node. 49174641Skmacy ExplodedNode *N = C.generateSink(State); 50237263Snp if (!N) 51237263Snp return; 52237263Snp 53176472Skmacy if (!BT) 54237263Snp BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration")); 55176472Skmacy 56176472Skmacy SmallString<256> buf; 57176472Skmacy llvm::raw_svector_ostream os(buf); 58176472Skmacy os << "Declared variable-length array (VLA) "; 59176472Skmacy switch (Kind) { 60176472Skmacy case VLA_Garbage: 61237263Snp os << "uses a garbage value as its size"; 62237263Snp break; 63174641Skmacy case VLA_Zero: 64237263Snp os << "has zero size"; 65237263Snp break; 66174641Skmacy case VLA_Tainted: 67176472Skmacy os << "has tainted size"; 68176472Skmacy break; 69174641Skmacy } 70174641Skmacy 71174641Skmacy BugReport *report = new BugReport(*BT, os.str(), N); 72174641Skmacy report->addRange(SizeE->getSourceRange()); 73174641Skmacy bugreporter::trackNullOrUndefValue(N, SizeE, *report); 74174641Skmacy C.emitReport(report); 75174641Skmacy return; 76174641Skmacy} 77174641Skmacy 78174641Skmacyvoid VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 79174641Skmacy if (!DS->isSingleDecl()) 80174641Skmacy return; 81174641Skmacy 82174641Skmacy const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 83174641Skmacy if (!VD) 84176472Skmacy return; 85174641Skmacy 86174641Skmacy ASTContext &Ctx = C.getASTContext(); 87174641Skmacy const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 88174641Skmacy if (!VLA) 89174641Skmacy return; 90174641Skmacy 91174641Skmacy // FIXME: Handle multi-dimensional VLAs. 92174641Skmacy const Expr *SE = VLA->getSizeExpr(); 93174641Skmacy ProgramStateRef state = C.getState(); 94174641Skmacy SVal sizeV = state->getSVal(SE, C.getLocationContext()); 95174641Skmacy 96 if (sizeV.isUndef()) { 97 reportBug(VLA_Garbage, SE, state, C); 98 return; 99 } 100 101 // See if the size value is known. It can't be undefined because we would have 102 // warned about that already. 103 if (sizeV.isUnknown()) 104 return; 105 106 // Check if the size is tainted. 107 if (state->isTainted(sizeV)) { 108 reportBug(VLA_Tainted, SE, 0, C); 109 return; 110 } 111 112 // Check if the size is zero. 113 DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); 114 115 ProgramStateRef stateNotZero, stateZero; 116 llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); 117 118 if (stateZero && !stateNotZero) { 119 reportBug(VLA_Zero, SE, stateZero, C); 120 return; 121 } 122 123 // From this point on, assume that the size is not zero. 124 state = stateNotZero; 125 126 // VLASizeChecker is responsible for defining the extent of the array being 127 // declared. We do this by multiplying the array length by the element size, 128 // then matching that with the array region's extent symbol. 129 130 // Convert the array length to size_t. 131 SValBuilder &svalBuilder = C.getSValBuilder(); 132 QualType SizeTy = Ctx.getSizeType(); 133 NonLoc ArrayLength = 134 svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>(); 135 136 // Get the element size. 137 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 138 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 139 140 // Multiply the array length by the element size. 141 SVal ArraySizeVal = svalBuilder.evalBinOpNN( 142 state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy); 143 144 // Finally, assume that the array's extent matches the given size. 145 const LocationContext *LC = C.getLocationContext(); 146 DefinedOrUnknownSVal Extent = 147 state->getRegion(VD, LC)->getExtent(svalBuilder); 148 DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>(); 149 DefinedOrUnknownSVal sizeIsKnown = 150 svalBuilder.evalEQ(state, Extent, ArraySize); 151 state = state->assume(sizeIsKnown, true); 152 153 // Assume should not fail at this point. 154 assert(state); 155 156 // Remember our assumptions! 157 C.addTransition(state); 158} 159 160void ento::registerVLASizeChecker(CheckerManager &mgr) { 161 mgr.registerChecker<VLASizeChecker>(); 162} 163