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 dereferenceable 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)), FR); 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)), 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 R); 192 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 193 } else { 194 IsAnyFieldInitialized = true; 195 return false; 196 } 197 } 198 199 if (PointeeT->isArrayType()) { 200 IsAnyFieldInitialized = true; 201 return false; 202 } 203 204 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && 205 "At this point FR must either have a primitive dynamic type, or it " 206 "must be a null, undefined, unknown or concrete pointer!"); 207 208 SVal PointeeV = State->getSVal(R); 209 210 if (isPrimitiveUninit(PointeeV)) { 211 if (NeedsCastBack) 212 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R); 213 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 214 } 215 216 IsAnyFieldInitialized = true; 217 return false; 218 } 219 220 //===----------------------------------------------------------------------===// 221 // Utility functions. 222 //===----------------------------------------------------------------------===// 223 224 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 225 const FieldRegion *FR) { 226 227 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; 228 229 SVal V = State->getSVal(FR); 230 assert(V.getAsRegion() && "V must have an underlying region!"); 231 232 // If the static type of the field is a void pointer, or it is a 233 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before 234 // dereferencing. 235 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) || 236 V.getAs<nonloc::LocAsInteger>(); 237 238 // The region we'd like to acquire. 239 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); 240 if (!R) 241 return None; 242 243 VisitedRegions.insert(R); 244 245 // We acquire the dynamic type of R, 246 QualType DynT = R->getLocationType(); 247 248 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { 249 250 R = Tmp->getAs<TypedValueRegion>(); 251 if (!R) 252 return None; 253 254 // We found a cyclic pointer, like int *ptr = (int *)&ptr. 255 if (!VisitedRegions.insert(R).second) 256 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true}; 257 258 DynT = R->getLocationType(); 259 // In order to ensure that this loop terminates, we're also checking the 260 // dynamic type of R, since type hierarchy is finite. 261 if (isDereferencableType(DynT->getPointeeType())) 262 break; 263 } 264 265 while (R->getAs<CXXBaseObjectRegion>()) { 266 NeedsCastBack = true; 267 268 if (!isa<TypedValueRegion>(R->getSuperRegion())) 269 break; 270 R = R->getSuperRegion()->getAs<TypedValueRegion>(); 271 } 272 273 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; 274 } 275 276 static bool isVoidPointer(QualType T) { 277 while (!T.isNull()) { 278 if (T->isVoidPointerType()) 279 return true; 280 T = T->getPointeeType(); 281 } 282 return false; 283 } 284