1 //===----- UninitializedPointer.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 a description what this checker does, 14 // refer to UninitializedObjectChecker.cpp. 15 // 16 // To read about how the checker works, refer to the comments in 17 // UninitializedObject.h. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #include "../ClangSACheckers.h" 22 #include "UninitializedObject.h" 23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 24 #include "clang/StaticAnalyzer/Core/Checker.h" 25 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 26 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" 27 28 using namespace clang; 29 using namespace clang::ento; 30 31 namespace { 32 33 /// Represents a pointer or a reference field. 34 class LocField final : public FieldNode { 35 /// We'll store whether the pointee or the pointer itself is uninitialited. 36 const bool IsDereferenced; 37 38 public: 39 LocField(const FieldRegion *FR, const bool IsDereferenced = true) 40 : FieldNode(FR), IsDereferenced(IsDereferenced) {} 41 42 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 43 if (IsDereferenced) 44 Out << "uninitialized pointee "; 45 else 46 Out << "uninitialized pointer "; 47 } 48 49 virtual void printPrefix(llvm::raw_ostream &Out) const override {} 50 51 virtual void printNode(llvm::raw_ostream &Out) const override { 52 Out << getVariableName(getDecl()); 53 } 54 55 virtual void printSeparator(llvm::raw_ostream &Out) const override { 56 if (getDecl()->getType()->isPointerType()) 57 Out << "->"; 58 else 59 Out << '.'; 60 } 61 }; 62 63 /// Represents a void* field that needs to be casted back to its dynamic type 64 /// for a correct note message. 65 class NeedsCastLocField final : public FieldNode { 66 QualType CastBackType; 67 68 public: 69 NeedsCastLocField(const FieldRegion *FR, const QualType &T) 70 : FieldNode(FR), CastBackType(T) {} 71 72 virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 73 Out << "uninitialized pointee "; 74 } 75 76 virtual void printPrefix(llvm::raw_ostream &Out) const override { 77 Out << "static_cast" << '<' << CastBackType.getAsString() << ">("; 78 } 79 80 virtual void printNode(llvm::raw_ostream &Out) const override { 81 Out << getVariableName(getDecl()) << ')'; 82 } 83 84 virtual void printSeparator(llvm::raw_ostream &Out) const override { 85 Out << "->"; 86 } 87 }; 88 89 } // end of anonymous namespace 90 91 // Utility function declarations. 92 93 /// Returns whether T can be (transitively) dereferenced to a void pointer type 94 /// (void*, void**, ...). The type of the region behind a void pointer isn't 95 /// known, and thus FD can not be analyzed. 96 static bool isVoidPointer(QualType T); 97 98 /// Dereferences \p V and returns the value and dynamic type of the pointee, as 99 /// well as whether \p FR needs to be casted back to that type. If for whatever 100 /// reason dereferencing fails, returns with None. 101 static llvm::Optional<std::tuple<SVal, QualType, bool>> 102 dereference(ProgramStateRef State, const FieldRegion *FR); 103 104 //===----------------------------------------------------------------------===// 105 // Methods for FindUninitializedFields. 106 //===----------------------------------------------------------------------===// 107 108 // Note that pointers/references don't contain fields themselves, so in this 109 // function we won't add anything to LocalChain. 110 bool FindUninitializedFields::isPointerOrReferenceUninit( 111 const FieldRegion *FR, FieldChainInfo LocalChain) { 112 113 assert((FR->getDecl()->getType()->isAnyPointerType() || 114 FR->getDecl()->getType()->isReferenceType() || 115 FR->getDecl()->getType()->isBlockPointerType()) && 116 "This method only checks pointer/reference objects!"); 117 118 SVal V = State->getSVal(FR); 119 120 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { 121 IsAnyFieldInitialized = true; 122 return false; 123 } 124 125 if (V.isUndef()) { 126 return addFieldToUninits( 127 LocalChain.add(LocField(FR, /*IsDereferenced*/ false))); 128 } 129 130 if (!CheckPointeeInitialization) { 131 IsAnyFieldInitialized = true; 132 return false; 133 } 134 135 // At this point the pointer itself is initialized and points to a valid 136 // location, we'll now check the pointee. 137 llvm::Optional<std::tuple<SVal, QualType, bool>> DerefInfo = 138 dereference(State, FR); 139 if (!DerefInfo) { 140 IsAnyFieldInitialized = true; 141 return false; 142 } 143 144 V = std::get<0>(*DerefInfo); 145 QualType DynT = std::get<1>(*DerefInfo); 146 bool NeedsCastBack = std::get<2>(*DerefInfo); 147 148 // If FR is a pointer pointing to a non-primitive type. 149 if (Optional<nonloc::LazyCompoundVal> RecordV = 150 V.getAs<nonloc::LazyCompoundVal>()) { 151 152 const TypedValueRegion *R = RecordV->getRegion(); 153 154 if (DynT->getPointeeType()->isStructureOrClassType()) { 155 if (NeedsCastBack) 156 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 157 return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 158 } 159 160 if (DynT->getPointeeType()->isUnionType()) { 161 if (isUnionUninit(R)) { 162 if (NeedsCastBack) 163 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); 164 return addFieldToUninits(LocalChain.add(LocField(FR))); 165 } else { 166 IsAnyFieldInitialized = true; 167 return false; 168 } 169 } 170 171 if (DynT->getPointeeType()->isArrayType()) { 172 IsAnyFieldInitialized = true; 173 return false; 174 } 175 176 llvm_unreachable("All cases are handled!"); 177 } 178 179 assert((isPrimitiveType(DynT->getPointeeType()) || DynT->isAnyPointerType() || 180 DynT->isReferenceType()) && 181 "At this point FR must either have a primitive dynamic type, or it " 182 "must be a null, undefined, unknown or concrete pointer!"); 183 184 if (isPrimitiveUninit(V)) { 185 if (NeedsCastBack) 186 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); 187 return addFieldToUninits(LocalChain.add(LocField(FR))); 188 } 189 190 IsAnyFieldInitialized = true; 191 return false; 192 } 193 194 //===----------------------------------------------------------------------===// 195 // Utility functions. 196 //===----------------------------------------------------------------------===// 197 198 static bool isVoidPointer(QualType T) { 199 while (!T.isNull()) { 200 if (T->isVoidPointerType()) 201 return true; 202 T = T->getPointeeType(); 203 } 204 return false; 205 } 206 207 static llvm::Optional<std::tuple<SVal, QualType, bool>> 208 dereference(ProgramStateRef State, const FieldRegion *FR) { 209 210 DynamicTypeInfo DynTInfo; 211 QualType DynT; 212 213 // If the static type of the field is a void pointer, we need to cast it back 214 // to the dynamic type before dereferencing. 215 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()); 216 217 SVal V = State->getSVal(FR); 218 assert(V.getAs<loc::MemRegionVal>() && "V must be loc::MemRegionVal!"); 219 220 // If V is multiple pointer value, we'll dereference it again (e.g.: int** -> 221 // int*). 222 // TODO: Dereference according to the dynamic type to avoid infinite loop for 223 // these kind of fields: 224 // int **ptr = reinterpret_cast<int **>(&ptr); 225 while (auto Tmp = V.getAs<loc::MemRegionVal>()) { 226 // We can't reason about symbolic regions, assume its initialized. 227 // Note that this also avoids a potential infinite recursion, because 228 // constructors for list-like classes are checked without being called, and 229 // the Static Analyzer will construct a symbolic region for Node *next; or 230 // similar code snippets. 231 if (Tmp->getRegion()->getSymbolicBase()) { 232 return None; 233 } 234 235 DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion()); 236 if (!DynTInfo.isValid()) { 237 return None; 238 } 239 240 DynT = DynTInfo.getType(); 241 242 if (isVoidPointer(DynT)) { 243 return None; 244 } 245 246 V = State->getSVal(*Tmp, DynT); 247 } 248 249 return std::make_tuple(V, DynT, NeedsCastBack); 250 } 251