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