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