VLASizeChecker.cpp revision 0bd6b110e908892d4b5c8671a9f435a1d72ad16a
105a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===// 205a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// 305a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// The LLVM Compiler Infrastructure 405a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// 505a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// This file is distributed under the University of Illinois Open Source 605a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// License. See LICENSE.TXT for details. 705a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// 805a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu//===----------------------------------------------------------------------===// 905a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// 10d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis// This defines VLASizeChecker, a builtin check in ExprEngine that 1105a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// performs checks for declaration of VLA of undefined or zero size. 12b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose// In addition, VLASizeChecker is responsible for defining the extent 13b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose// of the MemRegion that represents a VLA. 1405a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu// 1505a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu//===----------------------------------------------------------------------===// 1605a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu 173ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis#include "ClangSACheckers.h" 18ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 193ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 203ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 219b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 223ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis#include "clang/AST/CharUnits.h" 2305a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu 2405a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xuusing namespace clang; 259ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 2605a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu 2784b3595729d249d89b8b67a547e0992797e19793Ted Kremeneknamespace { 28ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { 293ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis mutable llvm::OwningPtr<BugType> BT_zero; 303ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis mutable llvm::OwningPtr<BugType> BT_undef; 3184b3595729d249d89b8b67a547e0992797e19793Ted Kremenek 3284b3595729d249d89b8b67a547e0992797e19793Ted Kremenekpublic: 333ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 3484b3595729d249d89b8b67a547e0992797e19793Ted Kremenek}; 3584b3595729d249d89b8b67a547e0992797e19793Ted Kremenek} // end anonymous namespace 3684b3595729d249d89b8b67a547e0992797e19793Ted Kremenek 373ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidisvoid VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 38ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!DS->isSingleDecl()) 39ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 40ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 41ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 42ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!VD) 43ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 4452e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 4552e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose ASTContext &Ctx = C.getASTContext(); 4652e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 47ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!VLA) 48ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 49ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 50ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek // FIXME: Handle multi-dimensional VLAs. 519c378f705405d37f49795d5e915989de774fe11fTed Kremenek const Expr *SE = VLA->getSizeExpr(); 5218c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek const ProgramState *state = C.getState(); 531397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek SVal sizeV = state->getSVal(SE); 54ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 55ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (sizeV.isUndef()) { 56ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek // Generate an error node. 57d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(); 58ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!N) 59ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 60ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 61ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!BT_undef) 623ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) " 633ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis "uses a garbage value as its size")); 64ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 65e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 66e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT_undef, BT_undef->getName(), N); 67ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek report->addRange(SE->getSourceRange()); 6850bbc165b063155cc23c360deb7b865502e068e2Anna Zaks report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE)); 69ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek C.EmitReport(report); 70ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 7105a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu } 7252e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 7352e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // See if the size value is known. It can't be undefined because we would have 7452e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // warned about that already. 7552e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose if (sizeV.isUnknown()) 7652e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose return; 77ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 78ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek // Check if the size is zero. 7952e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose DefinedSVal sizeD = cast<DefinedSVal>(sizeV); 80ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 8118c66fdc3c4008d335885695fe36fb5353c5f672Ted Kremenek const ProgramState *stateNotZero, *stateZero; 8228f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); 83ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 84ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (stateZero && !stateNotZero) { 859c378f705405d37f49795d5e915989de774fe11fTed Kremenek ExplodedNode *N = C.generateSink(stateZero); 86ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek if (!BT_zero) 873ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has " 883ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis "zero size")); 89ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 90e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 91e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT_zero, BT_zero->getName(), N); 92ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek report->addRange(SE->getSourceRange()); 9350bbc165b063155cc23c360deb7b865502e068e2Anna Zaks report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE)); 94ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek C.EmitReport(report); 95ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek return; 9605a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu } 97ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek 98ae1623345aed43dcd2e069970a00618378a37b34Ted Kremenek // From this point on, assume that the size is not zero. 9952e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose state = stateNotZero; 10052e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 101b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose // VLASizeChecker is responsible for defining the extent of the array being 102b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose // declared. We do this by multiplying the array length by the element size, 103b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose // then matching that with the array region's extent symbol. 104b2242d1b6fe4ae073361e6d8f3db751c95159ca5Jordy Rose 10552e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // Convert the array length to size_t. 106c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek SValBuilder &svalBuilder = C.getSValBuilder(); 10752e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose QualType SizeTy = Ctx.getSizeType(); 108c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy, 109c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek SE->getType())); 11052e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 11152e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // Get the element size. 11252e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 113c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 11452e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 11552e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // Multiply the array length by the element size. 116c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength, 117c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek cast<NonLoc>(EleSizeVal), SizeTy); 11852e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 11928f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek // Finally, assume that the array's extent matches the given size. 12052e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose const LocationContext *LC = C.getPredecessor()->getLocationContext(); 121c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek DefinedOrUnknownSVal Extent = 122c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek state->getRegion(VD, LC)->getExtent(svalBuilder); 12352e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal); 124c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek DefinedOrUnknownSVal sizeIsKnown = 125c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek svalBuilder.evalEQ(state, Extent, ArraySize); 126c8413fd03f73084a5c93028f8b4db619fc388087Ted Kremenek state = state->assume(sizeIsKnown, true); 12752e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose 128e4f5d72a504be32483aebdeb48fd2effce6756f2Zhongxing Xu // Assume should not fail at this point. 129e4f5d72a504be32483aebdeb48fd2effce6756f2Zhongxing Xu assert(state); 130e4f5d72a504be32483aebdeb48fd2effce6756f2Zhongxing Xu 13152e04c537633377fb14cfa4fa3c95e3e510fc942Jordy Rose // Remember our assumptions! 1320bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(state); 13305a2338f7ba1c8a0136e120502f80a38cf0e9fd3Zhongxing Xu} 1343ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis 1353ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidisvoid ento::registerVLASizeChecker(CheckerManager &mgr) { 1363ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis mgr.registerChecker<VLASizeChecker>(); 1373ce2b48461115af047ee1e957e1892af255bf120Argyrios Kyrtzidis} 138