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