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 void printNoteMsg(llvm::raw_ostream &Out) const override { 38 if (IsDereferenced) 39 Out << "uninitialized pointee "; 40 else 41 Out << "uninitialized pointer "; 42 } 43 44 void printPrefix(llvm::raw_ostream &Out) const override {} 45 46 void printNode(llvm::raw_ostream &Out) const override { 47 Out << getVariableName(getDecl()); 48 } 49 50 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 void printNoteMsg(llvm::raw_ostream &Out) const override { 68 Out << "uninitialized pointee "; 69 } 70 71 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 void printNode(llvm::raw_ostream &Out) const override { 82 Out << getVariableName(getDecl()) << ')'; 83 } 84 85 void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; } 86 }; 87 88 /// Represents a Loc field that points to itself. 89 class CyclicLocField final : public FieldNode { 90 91 public: 92 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} 93 94 void printNoteMsg(llvm::raw_ostream &Out) const override { 95 Out << "object references itself "; 96 } 97 98 void printPrefix(llvm::raw_ostream &Out) const override {} 99 100 void printNode(llvm::raw_ostream &Out) const override { 101 Out << getVariableName(getDecl()); 102 } 103 104 void printSeparator(llvm::raw_ostream &Out) const override { 105 llvm_unreachable("CyclicLocField objects must be the last node of the " 106 "fieldchain!"); 107 } 108 }; 109 110 } // end of anonymous namespace 111 112 // Utility function declarations. 113 114 struct DereferenceInfo { 115 const TypedValueRegion *R; 116 const bool NeedsCastBack; 117 const bool IsCyclic; 118 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) 119 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} 120 }; 121 122 /// Dereferences \p FR and returns with the pointee's region, and whether it 123 /// needs to be casted back to it's location type. If for whatever reason 124 /// dereferencing fails, returns with None. 125 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 126 const FieldRegion *FR); 127 128 /// Returns whether \p T can be (transitively) dereferenced to a void pointer 129 /// type (void*, void**, ...). 130 static bool isVoidPointer(QualType T); 131 132 //===----------------------------------------------------------------------===// 133 // Methods for FindUninitializedFields. 134 //===----------------------------------------------------------------------===// 135 136 bool FindUninitializedFields::isDereferencableUninit( 137 const FieldRegion *FR, FieldChainInfo LocalChain) { 138 139 SVal V = State->getSVal(FR); 140 141 assert((isDereferencableType(FR->getDecl()->getType()) || 142 isa<nonloc::LocAsInteger>(V)) && 143 "This method only checks dereferenceable objects!"); 144 145 if (V.isUnknown() || isa<loc::ConcreteInt>(V)) { 146 IsAnyFieldInitialized = true; 147 return false; 148 } 149 150 if (V.isUndef()) { 151 return addFieldToUninits( 152 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR); 153 } 154 155 if (!Opts.CheckPointeeInitialization) { 156 IsAnyFieldInitialized = true; 157 return false; 158 } 159 160 // At this point the pointer itself is initialized and points to a valid 161 // location, we'll now check the pointee. 162 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); 163 if (!DerefInfo) { 164 IsAnyFieldInitialized = true; 165 return false; 166 } 167 168 if (DerefInfo->IsCyclic) 169 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR); 170 171 const TypedValueRegion *R = DerefInfo->R; 172 const bool NeedsCastBack = DerefInfo->NeedsCastBack; 173 174 QualType DynT = R->getLocationType(); 175 QualType PointeeT = DynT->getPointeeType(); 176 177 if (PointeeT->isStructureOrClassType()) { 178 if (NeedsCastBack) 179 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 180 return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 181 } 182 183 if (PointeeT->isUnionType()) { 184 if (isUnionUninit(R)) { 185 if (NeedsCastBack) 186 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), 187 R); 188 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 189 } else { 190 IsAnyFieldInitialized = true; 191 return false; 192 } 193 } 194 195 if (PointeeT->isArrayType()) { 196 IsAnyFieldInitialized = true; 197 return false; 198 } 199 200 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && 201 "At this point FR must either have a primitive dynamic type, or it " 202 "must be a null, undefined, unknown or concrete pointer!"); 203 204 SVal PointeeV = State->getSVal(R); 205 206 if (isPrimitiveUninit(PointeeV)) { 207 if (NeedsCastBack) 208 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R); 209 return addFieldToUninits(LocalChain.add(LocField(FR)), R); 210 } 211 212 IsAnyFieldInitialized = true; 213 return false; 214 } 215 216 //===----------------------------------------------------------------------===// 217 // Utility functions. 218 //===----------------------------------------------------------------------===// 219 220 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 221 const FieldRegion *FR) { 222 223 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; 224 225 SVal V = State->getSVal(FR); 226 assert(V.getAsRegion() && "V must have an underlying region!"); 227 228 // If the static type of the field is a void pointer, or it is a 229 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before 230 // dereferencing. 231 bool NeedsCastBack = 232 isVoidPointer(FR->getDecl()->getType()) || isa<nonloc::LocAsInteger>(V); 233 234 // The region we'd like to acquire. 235 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); 236 if (!R) 237 return None; 238 239 VisitedRegions.insert(R); 240 241 // We acquire the dynamic type of R, 242 QualType DynT = R->getLocationType(); 243 244 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { 245 246 R = Tmp->getAs<TypedValueRegion>(); 247 if (!R) 248 return None; 249 250 // We found a cyclic pointer, like int *ptr = (int *)&ptr. 251 if (!VisitedRegions.insert(R).second) 252 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true}; 253 254 DynT = R->getLocationType(); 255 // In order to ensure that this loop terminates, we're also checking the 256 // dynamic type of R, since type hierarchy is finite. 257 if (isDereferencableType(DynT->getPointeeType())) 258 break; 259 } 260 261 while (isa<CXXBaseObjectRegion>(R)) { 262 NeedsCastBack = true; 263 const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion()); 264 if (!SuperR) 265 break; 266 267 R = SuperR; 268 } 269 270 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; 271 } 272 273 static bool isVoidPointer(QualType T) { 274 while (!T.isNull()) { 275 if (T->isVoidPointerType()) 276 return true; 277 T = T->getPointeeType(); 278 } 279 return false; 280 } 281