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 24 using namespace clang; 25 using namespace clang::ento; 26 27 namespace { 28 29 /// Represents a pointer or a reference field. 30 class LocField final : public FieldNode { 31 /// We'll store whether the pointee or the pointer itself is uninitialited. 32 const bool IsDereferenced; 33 34 public: 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. 61 class NeedsCastLocField final : public FieldNode { 62 QualType CastBackType; 63 64 public: 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. 92 class CyclicLocField final : public FieldNode { 93 94 public: 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 117 struct 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. 128 static 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**, ...). 133 static bool isVoidPointer(QualType T); 134 135 //===----------------------------------------------------------------------===// 136 // Methods for FindUninitializedFields. 137 //===----------------------------------------------------------------------===// 138 139 bool 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 223 static 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 275 static 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