1 //===----- UninitializedObject.h ---------------------------------*- 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 helper classes for UninitializedObjectChecker and 11 // documentation about the logic of it. 12 // 13 // To read about command line options and a description what this checker does, 14 // refer to UninitializedObjectChecker.cpp. 15 // 16 // Some methods are implemented in UninitializedPointee.cpp, to reduce the 17 // complexity of the main checker file. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #ifndef LLVM_CLANG_STATICANALYZER_UNINITIALIZEDOBJECT_H 22 #define LLVM_CLANG_STATICANALYZER_UNINITIALIZEDOBJECT_H 23 24 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25 26 namespace clang { 27 namespace ento { 28 29 /// Represent a single field. This is only an interface to abstract away special 30 /// cases like pointers/references. 31 class FieldNode { 32 protected: 33 const FieldRegion *FR; 34 35 ~FieldNode() = default; 36 37 public: 38 FieldNode(const FieldRegion *FR) : FR(FR) { assert(FR); } 39 40 FieldNode() = delete; 41 FieldNode(const FieldNode &) = delete; 42 FieldNode(FieldNode &&) = delete; 43 FieldNode &operator=(const FieldNode &) = delete; 44 FieldNode &operator=(const FieldNode &&) = delete; 45 46 /// Profile - Used to profile the contents of this object for inclusion in a 47 /// FoldingSet. 48 void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(this); } 49 50 bool operator<(const FieldNode &Other) const { return FR < Other.FR; } 51 bool isSameRegion(const FieldRegion *OtherFR) const { return FR == OtherFR; } 52 53 const FieldRegion *getRegion() const { return FR; } 54 const FieldDecl *getDecl() const { return FR->getDecl(); } 55 56 // When a fieldchain is printed (a list of FieldNode objects), it will have 57 // the following format: 58 // <note message>'<prefix>this-><node><separator><node><separator>...<node>' 59 60 /// If this is the last element of the fieldchain, this method will be called. 61 /// The note message should state something like "uninitialized field" or 62 /// "uninitialized pointee" etc. 63 virtual void printNoteMsg(llvm::raw_ostream &Out) const = 0; 64 65 /// Print any prefixes before the fieldchain. 66 virtual void printPrefix(llvm::raw_ostream &Out) const = 0; 67 68 /// Print the node. Should contain the name of the field stored in getRegion. 69 virtual void printNode(llvm::raw_ostream &Out) const = 0; 70 71 /// Print the separator. For example, fields may be separated with '.' or 72 /// "->". 73 virtual void printSeparator(llvm::raw_ostream &Out) const = 0; 74 }; 75 76 /// Returns with Field's name. This is a helper function to get the correct name 77 /// even if Field is a captured lambda variable. 78 StringRef getVariableName(const FieldDecl *Field); 79 80 /// Represents a field chain. A field chain is a vector of fields where the 81 /// first element of the chain is the object under checking (not stored), and 82 /// every other element is a field, and the element that precedes it is the 83 /// object that contains it. 84 /// 85 /// Note that this class is immutable (essentially a wrapper around an 86 /// ImmutableList), and new elements can only be added by creating new 87 /// FieldChainInfo objects through add(). 88 class FieldChainInfo { 89 public: 90 using FieldChainImpl = llvm::ImmutableListImpl<const FieldNode &>; 91 using FieldChain = llvm::ImmutableList<const FieldNode &>; 92 93 private: 94 FieldChain::Factory &ChainFactory; 95 FieldChain Chain; 96 97 public: 98 FieldChainInfo() = delete; 99 FieldChainInfo(FieldChain::Factory &F) : ChainFactory(F) {} 100 FieldChainInfo(const FieldChainInfo &Other) = default; 101 102 template <class FieldNodeT> FieldChainInfo add(const FieldNodeT &FN); 103 104 bool contains(const FieldRegion *FR) const; 105 const FieldRegion *getUninitRegion() const; 106 void printNoteMsg(llvm::raw_ostream &Out) const; 107 }; 108 109 using UninitFieldMap = std::map<const FieldRegion *, llvm::SmallString<50>>; 110 111 /// Searches for and stores uninitialized fields in a non-union object. 112 class FindUninitializedFields { 113 ProgramStateRef State; 114 const TypedValueRegion *const ObjectR; 115 116 const bool CheckPointeeInitialization; 117 bool IsAnyFieldInitialized = false; 118 119 FieldChainInfo::FieldChain::Factory ChainFactory; 120 121 /// A map for assigning uninitialized regions to note messages. For example, 122 /// 123 /// struct A { 124 /// int x; 125 /// }; 126 /// 127 /// A a; 128 /// 129 /// After analyzing `a`, the map will contain a pair for `a.x`'s region and 130 /// the note message "uninitialized field 'this->x'. 131 UninitFieldMap UninitFields; 132 133 public: 134 /// Constructs the FindUninitializedField object, searches for and stores 135 /// uninitialized fields in R. 136 FindUninitializedFields(ProgramStateRef State, 137 const TypedValueRegion *const R, 138 bool CheckPointeeInitialization); 139 140 const UninitFieldMap &getUninitFields() { return UninitFields; } 141 142 /// Returns whether the analyzed region contains at least one initialized 143 /// field. 144 bool isAnyFieldInitialized() { return IsAnyFieldInitialized; } 145 146 private: 147 // For the purposes of this checker, we'll regard the object under checking as 148 // a directed tree, where 149 // * the root is the object under checking 150 // * every node is an object that is 151 // - a union 152 // - a non-union record 153 // - a pointer/reference 154 // - an array 155 // - of a primitive type, which we'll define later in a helper function. 156 // * the parent of each node is the object that contains it 157 // * every leaf is an array, a primitive object, a nullptr or an undefined 158 // pointer. 159 // 160 // Example: 161 // 162 // struct A { 163 // struct B { 164 // int x, y = 0; 165 // }; 166 // B b; 167 // int *iptr = new int; 168 // B* bptr; 169 // 170 // A() {} 171 // }; 172 // 173 // The directed tree: 174 // 175 // ->x 176 // / 177 // ->b--->y 178 // / 179 // A-->iptr->(int value) 180 // \ 181 // ->bptr 182 // 183 // From this we'll construct a vector of fieldchains, where each fieldchain 184 // represents an uninitialized field. An uninitialized field may be a 185 // primitive object, a pointer, a pointee or a union without a single 186 // initialized field. 187 // In the above example, for the default constructor call we'll end up with 188 // these fieldchains: 189 // 190 // this->b.x 191 // this->iptr (pointee uninit) 192 // this->bptr (pointer uninit) 193 // 194 // We'll traverse each node of the above graph with the appropiate one of 195 // these methods: 196 197 /// This method checks a region of a union object, and returns true if no 198 /// field is initialized within the region. 199 bool isUnionUninit(const TypedValueRegion *R); 200 201 /// This method checks a region of a non-union object, and returns true if 202 /// an uninitialized field is found within the region. 203 bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain); 204 205 /// This method checks a region of a pointer or reference object, and returns 206 /// true if the ptr/ref object itself or any field within the pointee's region 207 /// is uninitialized. 208 bool isPointerOrReferenceUninit(const FieldRegion *FR, 209 FieldChainInfo LocalChain); 210 211 /// This method returns true if the value of a primitive object is 212 /// uninitialized. 213 bool isPrimitiveUninit(const SVal &V); 214 215 // Note that we don't have a method for arrays -- the elements of an array are 216 // often left uninitialized intentionally even when it is of a C++ record 217 // type, so we'll assume that an array is always initialized. 218 // TODO: Add a support for nonloc::LocAsInteger. 219 220 /// Processes LocalChain and attempts to insert it into UninitFields. Returns 221 /// true on success. 222 /// 223 /// Since this class analyzes regions with recursion, we'll only store 224 /// references to temporary FieldNode objects created on the stack. This means 225 /// that after analyzing a leaf of the directed tree described above, the 226 /// elements LocalChain references will be destructed, so we can't store it 227 /// directly. 228 bool addFieldToUninits(FieldChainInfo LocalChain); 229 }; 230 231 /// Returns true if T is a primitive type. We defined this type so that for 232 /// objects that we'd only like analyze as much as checking whether their 233 /// value is undefined or not, such as ints and doubles, can be analyzed with 234 /// ease. This also helps ensuring that every special field type is handled 235 /// correctly. 236 static bool isPrimitiveType(const QualType &T) { 237 return T->isBuiltinType() || T->isEnumeralType() || T->isMemberPointerType(); 238 } 239 240 // Template method definitions. 241 242 template <class FieldNodeT> 243 inline FieldChainInfo FieldChainInfo::add(const FieldNodeT &FN) { 244 assert(!contains(FN.getRegion()) && 245 "Can't add a field that is already a part of the " 246 "fieldchain! Is this a cyclic reference?"); 247 248 FieldChainInfo NewChain = *this; 249 NewChain.Chain = ChainFactory.add(FN, Chain); 250 return NewChain; 251 } 252 253 } // end of namespace ento 254 } // end of namespace clang 255 256 #endif // LLVM_CLANG_STATICANALYZER_UNINITIALIZEDOBJECT_H 257