clang API Documentation
00001 //=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines VLASizeChecker, a builtin check in ExprEngine that 00011 // performs checks for declaration of VLA of undefined or zero size. 00012 // In addition, VLASizeChecker is responsible for defining the extent 00013 // of the MemRegion that represents a VLA. 00014 // 00015 //===----------------------------------------------------------------------===// 00016 00017 #include "ClangSACheckers.h" 00018 #include "clang/StaticAnalyzer/Core/Checker.h" 00019 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00021 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00022 #include "clang/AST/CharUnits.h" 00023 #include "llvm/ADT/SmallString.h" 00024 #include "llvm/ADT/STLExtras.h" 00025 00026 using namespace clang; 00027 using namespace ento; 00028 00029 namespace { 00030 class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { 00031 mutable OwningPtr<BugType> BT; 00032 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted }; 00033 00034 void reportBug(VLASize_Kind Kind, 00035 const Expr *SizeE, 00036 ProgramStateRef State, 00037 CheckerContext &C) const; 00038 public: 00039 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 00040 }; 00041 } // end anonymous namespace 00042 00043 void VLASizeChecker::reportBug(VLASize_Kind Kind, 00044 const Expr *SizeE, 00045 ProgramStateRef State, 00046 CheckerContext &C) const { 00047 // Generate an error node. 00048 ExplodedNode *N = C.generateSink(State); 00049 if (!N) 00050 return; 00051 00052 if (!BT) 00053 BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration")); 00054 00055 SmallString<256> buf; 00056 llvm::raw_svector_ostream os(buf); 00057 os << "Declared variable-length array (VLA) "; 00058 switch (Kind) { 00059 case VLA_Garbage: 00060 os << "uses a garbage value as its size"; 00061 break; 00062 case VLA_Zero: 00063 os << "has zero size"; 00064 break; 00065 case VLA_Tainted: 00066 os << "has tainted size"; 00067 break; 00068 } 00069 00070 BugReport *report = new BugReport(*BT, os.str(), N); 00071 report->addRange(SizeE->getSourceRange()); 00072 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE, 00073 report)); 00074 C.EmitReport(report); 00075 return; 00076 } 00077 00078 void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 00079 if (!DS->isSingleDecl()) 00080 return; 00081 00082 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 00083 if (!VD) 00084 return; 00085 00086 ASTContext &Ctx = C.getASTContext(); 00087 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 00088 if (!VLA) 00089 return; 00090 00091 // FIXME: Handle multi-dimensional VLAs. 00092 const Expr *SE = VLA->getSizeExpr(); 00093 ProgramStateRef state = C.getState(); 00094 SVal sizeV = state->getSVal(SE, C.getLocationContext()); 00095 00096 if (sizeV.isUndef()) { 00097 reportBug(VLA_Garbage, SE, state, C); 00098 return; 00099 } 00100 00101 // See if the size value is known. It can't be undefined because we would have 00102 // warned about that already. 00103 if (sizeV.isUnknown()) 00104 return; 00105 00106 // Check if the size is tainted. 00107 if (state->isTainted(sizeV)) { 00108 reportBug(VLA_Tainted, SE, 0, C); 00109 return; 00110 } 00111 00112 // Check if the size is zero. 00113 DefinedSVal sizeD = cast<DefinedSVal>(sizeV); 00114 00115 ProgramStateRef stateNotZero, stateZero; 00116 llvm::tie(stateNotZero, stateZero) = state->assume(sizeD); 00117 00118 if (stateZero && !stateNotZero) { 00119 reportBug(VLA_Zero, SE, stateZero, C); 00120 return; 00121 } 00122 00123 // From this point on, assume that the size is not zero. 00124 state = stateNotZero; 00125 00126 // VLASizeChecker is responsible for defining the extent of the array being 00127 // declared. We do this by multiplying the array length by the element size, 00128 // then matching that with the array region's extent symbol. 00129 00130 // Convert the array length to size_t. 00131 SValBuilder &svalBuilder = C.getSValBuilder(); 00132 QualType SizeTy = Ctx.getSizeType(); 00133 NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy, 00134 SE->getType())); 00135 00136 // Get the element size. 00137 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 00138 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 00139 00140 // Multiply the array length by the element size. 00141 SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength, 00142 cast<NonLoc>(EleSizeVal), SizeTy); 00143 00144 // Finally, assume that the array's extent matches the given size. 00145 const LocationContext *LC = C.getLocationContext(); 00146 DefinedOrUnknownSVal Extent = 00147 state->getRegion(VD, LC)->getExtent(svalBuilder); 00148 DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal); 00149 DefinedOrUnknownSVal sizeIsKnown = 00150 svalBuilder.evalEQ(state, Extent, ArraySize); 00151 state = state->assume(sizeIsKnown, true); 00152 00153 // Assume should not fail at this point. 00154 assert(state); 00155 00156 // Remember our assumptions! 00157 C.addTransition(state); 00158 } 00159 00160 void ento::registerVLASizeChecker(CheckerManager &mgr) { 00161 mgr.registerChecker<VLASizeChecker>(); 00162 }