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 "../ClangSACheckers.h" 19 #include "UninitializedObject.h" 20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21 #include "clang/StaticAnalyzer/Core/Checker.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" 24 25 using namespace clang; 26 using namespace clang::ento; 27 28 namespace { 29 30 /// Represents a pointer or a reference field. 31 class LocField final : public FieldNode { 32 /// We'll store whether the pointee or the pointer itself is uninitialited. 33 const bool IsDereferenced; 34 35 public: 36 LocField(const FieldRegion *FR, const bool IsDereferenced = true) 37 : FieldNode(FR), IsDereferenced(IsDereferenced) {} 38 39 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 40 if (IsDereferenced) 41 Out << "uninitialized pointee "; 42 else 43 Out << "uninitialized pointer "; 44 } 45 46 virtual void printPrefix(llvm::raw_ostream &Out) const override {} 47 48 virtual void printNode(llvm::raw_ostream &Out) const override { 49 Out << getVariableName(getDecl()); 50 } 51 52 virtual void printSeparator(llvm::raw_ostream &Out) const override { 53 if (getDecl()->getType()->isPointerType()) 54 Out << "->"; 55 else 56 Out << '.'; 57 } 58 }; 59 60 /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but 61 /// needs to be casted back to its dynamic type for a correct note message. 62 class NeedsCastLocField final : public FieldNode { 63 QualType CastBackType; 64 65 public: 66 NeedsCastLocField(const FieldRegion *FR, const QualType &T) 67 : FieldNode(FR), CastBackType(T) {} 68 69 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 70 Out << "uninitialized pointee "; 71 } 72 73 virtual void printPrefix(llvm::raw_ostream &Out) const override { 74 // If this object is a nonloc::LocAsInteger. 75 if (getDecl()->getType()->isIntegerType()) 76 Out << "reinterpret_cast"; 77 // If this pointer's dynamic type is different then it's static type. 78 else 79 Out << "static_cast"; 80 Out << '<' << CastBackType.getAsString() << ">("; 81 } 82 83 virtual void printNode(llvm::raw_ostream &Out) const override { 84 Out << getVariableName(getDecl()) << ')'; 85 } 86 87 virtual void printSeparator(llvm::raw_ostream &Out) const override { 88 Out << "->"; 89 } 90 }; 91 92 /// Represents a Loc field that points to itself. 93 class CyclicLocField final : public FieldNode { 94 95 public: 96 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} 97 98 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 99 Out << "object references itself "; 100 } 101 102 virtual void printPrefix(llvm::raw_ostream &Out) const override {} 103 104 virtual void printNode(llvm::raw_ostream &Out) const override { 105 Out << getVariableName(getDecl()); 106 } 107 108 virtual void printSeparator(llvm::raw_ostream &Out) const override { 109 llvm_unreachable("CyclicLocField objects must be the last node of the " 110 "fieldchain!"); 111 } 112 }; 113 114 } // end of anonymous namespace 115 116 // Utility function declarations. 117 118 struct DereferenceInfo { 119 const TypedValueRegion *R; 120 const bool NeedsCastBack; 121 const bool IsCyclic; 122 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) 123 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} 124 }; 125 126 /// Dereferences \p FR and returns with the pointee's region, and whether it 127 /// needs to be casted back to it's location type. If for whatever reason 128 /// dereferencing fails, returns with None. 129 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 130 const FieldRegion *FR); 131 132 /// Returns whether \p T can be (transitively) dereferenced to a void pointer 133 /// type (void*, void**, ...). 134 static bool isVoidPointer(QualType T); 135 136 //===----------------------------------------------------------------------===// 137 // Methods for FindUninitializedFields. 138 //===----------------------------------------------------------------------===// 139 140 bool FindUninitializedFields::isDereferencableUninit( 141 const FieldRegion *FR, FieldChainInfo LocalChain) { 142 143 SVal V = State->getSVal(FR); 144 145 assert((isDereferencableType(FR->getDecl()->getType()) || 146 V.getAs<nonloc::LocAsInteger>()) && 147 "This method only checks dereferencable objects!"); 148 149 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { 150 IsAnyFieldInitialized = true; 151 return false; 152 } 153 154 if (V.isUndef()) { 155 return addFieldToUninits( 156 LocalChain.add(LocField(FR, /*IsDereferenced*/ false))); 157 } 158 159 if (!Opts.CheckPointeeInitialization) { 160 IsAnyFieldInitialized = true; 161 return false; 162 } 163 164 // At this point the pointer itself is initialized and points to a valid 165 // location, we'll now check the pointee. 166 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); 167 if (!DerefInfo) { 168 IsAnyFieldInitialized = true; 169 return false; 170 } 171 172 if (DerefInfo->IsCyclic) 173 return addFieldToUninits(LocalChain.add(CyclicLocField(FR))); 174 175 const TypedValueRegion *R = DerefInfo->R; 176 const bool NeedsCastBack = DerefInfo->NeedsCastBack; 177 178 QualType DynT = R->getLocationType(); 179 QualType PointeeT = DynT->getPointeeType(); 180 181 if (PointeeT->isStructureOrClassType()) { 182 if (NeedsCastBack) 183 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 184 return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 185 } 186 187 if (PointeeT->isUnionType()) { 188 if (isUnionUninit(R)) { 189 if (NeedsCastBack) 190 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); 191 return addFieldToUninits(LocalChain.add(LocField(FR))); 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))); 212 return addFieldToUninits(LocalChain.add(LocField(FR))); 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