UninitializedPointee.cpp revision 344779
1//===----- UninitializedPointee.cpp ------------------------------*- 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 file defines functions and methods for handling pointers and references 11// to reduce the size and complexity of UninitializedObjectChecker.cpp. 12// 13// To read about command line options and documentation about how the checker 14// works, refer to UninitializedObjectChecker.h. 15// 16//===----------------------------------------------------------------------===// 17 18#include "UninitializedObject.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20#include "clang/StaticAnalyzer/Core/Checker.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" 23 24using namespace clang; 25using namespace clang::ento; 26 27namespace { 28 29/// Represents a pointer or a reference field. 30class LocField final : public FieldNode { 31 /// We'll store whether the pointee or the pointer itself is uninitialited. 32 const bool IsDereferenced; 33 34public: 35 LocField(const FieldRegion *FR, const bool IsDereferenced = true) 36 : FieldNode(FR), IsDereferenced(IsDereferenced) {} 37 38 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 39 if (IsDereferenced) 40 Out << "uninitialized pointee "; 41 else 42 Out << "uninitialized pointer "; 43 } 44 45 virtual void printPrefix(llvm::raw_ostream &Out) const override {} 46 47 virtual void printNode(llvm::raw_ostream &Out) const override { 48 Out << getVariableName(getDecl()); 49 } 50 51 virtual void printSeparator(llvm::raw_ostream &Out) const override { 52 if (getDecl()->getType()->isPointerType()) 53 Out << "->"; 54 else 55 Out << '.'; 56 } 57}; 58 59/// Represents a nonloc::LocAsInteger or void* field, that point to objects, but 60/// needs to be casted back to its dynamic type for a correct note message. 61class NeedsCastLocField final : public FieldNode { 62 QualType CastBackType; 63 64public: 65 NeedsCastLocField(const FieldRegion *FR, const QualType &T) 66 : FieldNode(FR), CastBackType(T) {} 67 68 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 69 Out << "uninitialized pointee "; 70 } 71 72 virtual void printPrefix(llvm::raw_ostream &Out) const override { 73 // If this object is a nonloc::LocAsInteger. 74 if (getDecl()->getType()->isIntegerType()) 75 Out << "reinterpret_cast"; 76 // If this pointer's dynamic type is different then it's static type. 77 else 78 Out << "static_cast"; 79 Out << '<' << CastBackType.getAsString() << ">("; 80 } 81 82 virtual void printNode(llvm::raw_ostream &Out) const override { 83 Out << getVariableName(getDecl()) << ')'; 84 } 85 86 virtual void printSeparator(llvm::raw_ostream &Out) const override { 87 Out << "->"; 88 } 89}; 90 91/// Represents a Loc field that points to itself. 92class CyclicLocField final : public FieldNode { 93 94public: 95 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} 96 97 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 98 Out << "object references itself "; 99 } 100 101 virtual void printPrefix(llvm::raw_ostream &Out) const override {} 102 103 virtual void printNode(llvm::raw_ostream &Out) const override { 104 Out << getVariableName(getDecl()); 105 } 106 107 virtual void printSeparator(llvm::raw_ostream &Out) const override { 108 llvm_unreachable("CyclicLocField objects must be the last node of the " 109 "fieldchain!"); 110 } 111}; 112 113} // end of anonymous namespace 114 115// Utility function declarations. 116 117struct DereferenceInfo { 118 const TypedValueRegion *R; 119 const bool NeedsCastBack; 120 const bool IsCyclic; 121 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) 122 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} 123}; 124 125/// Dereferences \p FR and returns with the pointee's region, and whether it 126/// needs to be casted back to it's location type. If for whatever reason 127/// dereferencing fails, returns with None. 128static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 129 const FieldRegion *FR); 130 131/// Returns whether \p T can be (transitively) dereferenced to a void pointer 132/// type (void*, void**, ...). 133static bool isVoidPointer(QualType T); 134 135//===----------------------------------------------------------------------===// 136// Methods for FindUninitializedFields. 137//===----------------------------------------------------------------------===// 138 139bool FindUninitializedFields::isDereferencableUninit( 140 const FieldRegion *FR, FieldChainInfo LocalChain) { 141 142 SVal V = State->getSVal(FR); 143 144 assert((isDereferencableType(FR->getDecl()->getType()) || 145 V.getAs<nonloc::LocAsInteger>()) && 146 "This method only checks dereferenceable objects!"); 147 148 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { 149 IsAnyFieldInitialized = true; 150 return false; 151 } 152 153 if (V.isUndef()) { 154 return addFieldToUninits( 155 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR); 156 } 157 158 if (!Opts.CheckPointeeInitialization) { 159 IsAnyFieldInitialized = true; 160 return false; 161 } 162 163 // At this point the pointer itself is initialized and points to a valid 164 // location, we'll now check the pointee. 165 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); 166 if (!DerefInfo) { 167 IsAnyFieldInitialized = true; 168 return false; 169 } 170 171 if (DerefInfo->IsCyclic) 172 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR); 173 174 const TypedValueRegion *R = DerefInfo->R; 175 const bool NeedsCastBack = DerefInfo->NeedsCastBack; 176 177 QualType DynT = R->getLocationType(); 178 QualType PointeeT = DynT->getPointeeType(); 179 180 if (PointeeT->isStructureOrClassType()) { 181 if (NeedsCastBack) 182 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 183 return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 184 } 185 186 if (PointeeT->isUnionType()) { 187 if (isUnionUninit(R)) { 188 if (NeedsCastBack) 189 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), 190 R); 191 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 192 } else { 193 IsAnyFieldInitialized = true; 194 return false; 195 } 196 } 197 198 if (PointeeT->isArrayType()) { 199 IsAnyFieldInitialized = true; 200 return false; 201 } 202 203 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && 204 "At this point FR must either have a primitive dynamic type, or it " 205 "must be a null, undefined, unknown or concrete pointer!"); 206 207 SVal PointeeV = State->getSVal(R); 208 209 if (isPrimitiveUninit(PointeeV)) { 210 if (NeedsCastBack) 211 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R); 212 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 213 } 214 215 IsAnyFieldInitialized = true; 216 return false; 217} 218 219//===----------------------------------------------------------------------===// 220// Utility functions. 221//===----------------------------------------------------------------------===// 222 223static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 224 const FieldRegion *FR) { 225 226 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; 227 228 SVal V = State->getSVal(FR); 229 assert(V.getAsRegion() && "V must have an underlying region!"); 230 231 // If the static type of the field is a void pointer, or it is a 232 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before 233 // dereferencing. 234 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) || 235 V.getAs<nonloc::LocAsInteger>(); 236 237 // The region we'd like to acquire. 238 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); 239 if (!R) 240 return None; 241 242 VisitedRegions.insert(R); 243 244 // We acquire the dynamic type of R, 245 QualType DynT = R->getLocationType(); 246 247 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { 248 249 R = Tmp->getAs<TypedValueRegion>(); 250 if (!R) 251 return None; 252 253 // We found a cyclic pointer, like int *ptr = (int *)&ptr. 254 if (!VisitedRegions.insert(R).second) 255 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true}; 256 257 DynT = R->getLocationType(); 258 // In order to ensure that this loop terminates, we're also checking the 259 // dynamic type of R, since type hierarchy is finite. 260 if (isDereferencableType(DynT->getPointeeType())) 261 break; 262 } 263 264 while (R->getAs<CXXBaseObjectRegion>()) { 265 NeedsCastBack = true; 266 267 if (!isa<TypedValueRegion>(R->getSuperRegion())) 268 break; 269 R = R->getSuperRegion()->getAs<TypedValueRegion>(); 270 } 271 272 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; 273} 274 275static bool isVoidPointer(QualType T) { 276 while (!T.isNull()) { 277 if (T->isVoidPointerType()) 278 return true; 279 T = T->getPointeeType(); 280 } 281 return false; 282} 283