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/AST/CharUnits.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00020 #include "clang/StaticAnalyzer/Core/Checker.h" 00021 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00022 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00023 #include "llvm/ADT/STLExtras.h" 00024 #include "llvm/ADT/SmallString.h" 00025 #include "llvm/Support/raw_ostream.h" 00026 00027 using namespace clang; 00028 using namespace ento; 00029 00030 namespace { 00031 class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { 00032 mutable std::unique_ptr<BugType> BT; 00033 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative }; 00034 00035 void reportBug(VLASize_Kind Kind, 00036 const Expr *SizeE, 00037 ProgramStateRef State, 00038 CheckerContext &C) const; 00039 public: 00040 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 00041 }; 00042 } // end anonymous namespace 00043 00044 void VLASizeChecker::reportBug(VLASize_Kind Kind, 00045 const Expr *SizeE, 00046 ProgramStateRef State, 00047 CheckerContext &C) const { 00048 // Generate an error node. 00049 ExplodedNode *N = C.generateSink(State); 00050 if (!N) 00051 return; 00052 00053 if (!BT) 00054 BT.reset(new BuiltinBug( 00055 this, "Dangerous variable-length array (VLA) declaration")); 00056 00057 SmallString<256> buf; 00058 llvm::raw_svector_ostream os(buf); 00059 os << "Declared variable-length array (VLA) "; 00060 switch (Kind) { 00061 case VLA_Garbage: 00062 os << "uses a garbage value as its size"; 00063 break; 00064 case VLA_Zero: 00065 os << "has zero size"; 00066 break; 00067 case VLA_Tainted: 00068 os << "has tainted size"; 00069 break; 00070 case VLA_Negative: 00071 os << "has negative size"; 00072 break; 00073 } 00074 00075 BugReport *report = new BugReport(*BT, os.str(), N); 00076 report->addRange(SizeE->getSourceRange()); 00077 bugreporter::trackNullOrUndefValue(N, SizeE, *report); 00078 C.emitReport(report); 00079 return; 00080 } 00081 00082 void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 00083 if (!DS->isSingleDecl()) 00084 return; 00085 00086 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); 00087 if (!VD) 00088 return; 00089 00090 ASTContext &Ctx = C.getASTContext(); 00091 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); 00092 if (!VLA) 00093 return; 00094 00095 // FIXME: Handle multi-dimensional VLAs. 00096 const Expr *SE = VLA->getSizeExpr(); 00097 ProgramStateRef state = C.getState(); 00098 SVal sizeV = state->getSVal(SE, C.getLocationContext()); 00099 00100 if (sizeV.isUndef()) { 00101 reportBug(VLA_Garbage, SE, state, C); 00102 return; 00103 } 00104 00105 // See if the size value is known. It can't be undefined because we would have 00106 // warned about that already. 00107 if (sizeV.isUnknown()) 00108 return; 00109 00110 // Check if the size is tainted. 00111 if (state->isTainted(sizeV)) { 00112 reportBug(VLA_Tainted, SE, nullptr, C); 00113 return; 00114 } 00115 00116 // Check if the size is zero. 00117 DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); 00118 00119 ProgramStateRef stateNotZero, stateZero; 00120 std::tie(stateNotZero, stateZero) = state->assume(sizeD); 00121 00122 if (stateZero && !stateNotZero) { 00123 reportBug(VLA_Zero, SE, stateZero, C); 00124 return; 00125 } 00126 00127 // From this point on, assume that the size is not zero. 00128 state = stateNotZero; 00129 00130 // VLASizeChecker is responsible for defining the extent of the array being 00131 // declared. We do this by multiplying the array length by the element size, 00132 // then matching that with the array region's extent symbol. 00133 00134 // Check if the size is negative. 00135 SValBuilder &svalBuilder = C.getSValBuilder(); 00136 00137 QualType Ty = SE->getType(); 00138 DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty); 00139 00140 SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty); 00141 if (Optional<DefinedSVal> LessThanZeroDVal = 00142 LessThanZeroVal.getAs<DefinedSVal>()) { 00143 ConstraintManager &CM = C.getConstraintManager(); 00144 ProgramStateRef StatePos, StateNeg; 00145 00146 std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal); 00147 if (StateNeg && !StatePos) { 00148 reportBug(VLA_Negative, SE, state, C); 00149 return; 00150 } 00151 state = StatePos; 00152 } 00153 00154 // Convert the array length to size_t. 00155 QualType SizeTy = Ctx.getSizeType(); 00156 NonLoc ArrayLength = 00157 svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>(); 00158 00159 // Get the element size. 00160 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); 00161 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); 00162 00163 // Multiply the array length by the element size. 00164 SVal ArraySizeVal = svalBuilder.evalBinOpNN( 00165 state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy); 00166 00167 // Finally, assume that the array's extent matches the given size. 00168 const LocationContext *LC = C.getLocationContext(); 00169 DefinedOrUnknownSVal Extent = 00170 state->getRegion(VD, LC)->getExtent(svalBuilder); 00171 DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>(); 00172 DefinedOrUnknownSVal sizeIsKnown = 00173 svalBuilder.evalEQ(state, Extent, ArraySize); 00174 state = state->assume(sizeIsKnown, true); 00175 00176 // Assume should not fail at this point. 00177 assert(state); 00178 00179 // Remember our assumptions! 00180 C.addTransition(state); 00181 } 00182 00183 void ento::registerVLASizeChecker(CheckerManager &mgr) { 00184 mgr.registerChecker<VLASizeChecker>(); 00185 }