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 : 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 } // end of anonymous namespace 93 94 // Utility function declarations. 95 96 /// Returns whether \p T can be (transitively) dereferenced to a void pointer 97 /// type (void*, void**, ...). 98 static bool isVoidPointer(QualType T); 99 100 using DereferenceInfo = std::pair<const TypedValueRegion *, bool>; 101 102 /// Dereferences \p FR and returns with the pointee's region, and whether it 103 /// needs to be casted back to it's location type. If for whatever reason 104 /// dereferencing fails, returns with None. 105 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 106 const FieldRegion *FR); 107 108 //===----------------------------------------------------------------------===// 109 // Methods for FindUninitializedFields. 110 //===----------------------------------------------------------------------===// 111 112 bool FindUninitializedFields::isDereferencableUninit( 113 const FieldRegion *FR, FieldChainInfo LocalChain) { 114 115 SVal V = State->getSVal(FR); 116 117 assert((isDereferencableType(FR->getDecl()->getType()) || 118 V.getAs<nonloc::LocAsInteger>()) && 119 "This method only checks dereferencable objects!"); 120 121 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { 122 IsAnyFieldInitialized = true; 123 return false; 124 } 125 126 if (V.isUndef()) { 127 return addFieldToUninits( 128 LocalChain.add(LocField(FR, /*IsDereferenced*/ false))); 129 } 130 131 if (!Opts.CheckPointeeInitialization) { 132 IsAnyFieldInitialized = true; 133 return false; 134 } 135 136 // At this point the pointer itself is initialized and points to a valid 137 // location, we'll now check the pointee. 138 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); 139 if (!DerefInfo) { 140 IsAnyFieldInitialized = true; 141 return false; 142 } 143 144 const TypedValueRegion *R = DerefInfo->first; 145 const bool NeedsCastBack = DerefInfo->second; 146 147 QualType DynT = R->getLocationType(); 148 QualType PointeeT = DynT->getPointeeType(); 149 150 if (PointeeT->isStructureOrClassType()) { 151 if (NeedsCastBack) 152 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 153 return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 154 } 155 156 if (PointeeT->isUnionType()) { 157 if (isUnionUninit(R)) { 158 if (NeedsCastBack) 159 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); 160 return addFieldToUninits(LocalChain.add(LocField(FR))); 161 } else { 162 IsAnyFieldInitialized = true; 163 return false; 164 } 165 } 166 167 if (PointeeT->isArrayType()) { 168 IsAnyFieldInitialized = true; 169 return false; 170 } 171 172 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && 173 "At this point FR must either have a primitive dynamic type, or it " 174 "must be a null, undefined, unknown or concrete pointer!"); 175 176 SVal PointeeV = State->getSVal(R); 177 178 if (isPrimitiveUninit(PointeeV)) { 179 if (NeedsCastBack) 180 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); 181 return addFieldToUninits(LocalChain.add(LocField(FR))); 182 } 183 184 IsAnyFieldInitialized = true; 185 return false; 186 } 187 188 //===----------------------------------------------------------------------===// 189 // Utility functions. 190 //===----------------------------------------------------------------------===// 191 192 static bool isVoidPointer(QualType T) { 193 while (!T.isNull()) { 194 if (T->isVoidPointerType()) 195 return true; 196 T = T->getPointeeType(); 197 } 198 return false; 199 } 200 201 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 202 const FieldRegion *FR) { 203 204 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; 205 206 SVal V = State->getSVal(FR); 207 assert(V.getAsRegion() && "V must have an underlying region!"); 208 209 // If the static type of the field is a void pointer, or it is a 210 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before 211 // dereferencing. 212 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) || 213 V.getAs<nonloc::LocAsInteger>(); 214 215 // The region we'd like to acquire. 216 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); 217 if (!R) 218 return None; 219 220 VisitedRegions.insert(R); 221 222 // We acquire the dynamic type of R, 223 QualType DynT = R->getLocationType(); 224 225 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { 226 227 R = Tmp->getAs<TypedValueRegion>(); 228 if (!R) 229 return None; 230 231 // We found a cyclic pointer, like int *ptr = (int *)&ptr. 232 // TODO: Should we report these fields too? 233 if (!VisitedRegions.insert(R).second) 234 return None; 235 236 DynT = R->getLocationType(); 237 // In order to ensure that this loop terminates, we're also checking the 238 // dynamic type of R, since type hierarchy is finite. 239 if (isDereferencableType(DynT->getPointeeType())) 240 break; 241 } 242 243 while (R->getAs<CXXBaseObjectRegion>()) { 244 NeedsCastBack = true; 245 246 if (!isa<TypedValueRegion>(R->getSuperRegion())) 247 break; 248 R = R->getSuperRegion()->getAs<TypedValueRegion>(); 249 } 250 251 return std::make_pair(R, NeedsCastBack); 252 } 253