blob: 095a1e607d808e44d8ecdd62f8a79fb9a97ace44 [file] [log] [blame]
Kristof Umann56963ae2018-08-13 18:17:05 +00001//===----- 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
26namespace clang {
27namespace ento {
28
Kristof Umann015b0592018-08-13 18:43:08 +000029/// Represent a single field. This is only an interface to abstract away special
30/// cases like pointers/references.
31class FieldNode {
32protected:
33 const FieldRegion *FR;
34
35public:
36 FieldNode(const FieldRegion *FR) : FR(FR) { assert(FR); }
37
38 FieldNode() = delete;
39 FieldNode(const FieldNode &) = delete;
40 FieldNode(FieldNode &&) = delete;
41 FieldNode &operator=(const FieldNode &) = delete;
42 FieldNode &operator=(const FieldNode &&) = delete;
43
44 /// Profile - Used to profile the contents of this object for inclusion in a
45 /// FoldingSet.
46 void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(this); }
47
48 bool operator<(const FieldNode &Other) const { return FR < Other.FR; }
49 bool isSameRegion(const FieldRegion *OtherFR) const { return FR == OtherFR; }
50
51 const FieldRegion *getRegion() const { return FR; }
52 const FieldDecl *getDecl() const { return FR->getDecl(); }
53
54 // When a fieldchain is printed (a list of FieldNode objects), it will have
55 // the following format:
56 // <note message>'<prefix>this-><node><separator><node><separator>...<node>'
57
58 /// If this is the last element of the fieldchain, this method will be called.
59 /// The note message should state something like "uninitialized field" or
60 /// "uninitialized pointee" etc.
61 virtual void printNoteMsg(llvm::raw_ostream &Out) const = 0;
62
63 /// Print any prefixes before the fieldchain.
64 virtual void printPrefix(llvm::raw_ostream &Out) const = 0;
65
66 /// Print the node. Should contain the name of the field stored in getRegion.
67 virtual void printNode(llvm::raw_ostream &Out) const = 0;
68
69 /// Print the separator. For example, fields may be separated with '.' or
70 /// "->".
71 virtual void printSeparator(llvm::raw_ostream &Out) const = 0;
72};
73
74/// Returns with Field's name. This is a helper function to get the correct name
75/// even if Field is a captured lambda variable.
76StringRef getVariableName(const FieldDecl *Field);
77
Kristof Umann56963ae2018-08-13 18:17:05 +000078/// Represents a field chain. A field chain is a vector of fields where the
79/// first element of the chain is the object under checking (not stored), and
80/// every other element is a field, and the element that precedes it is the
81/// object that contains it.
82///
Kristof Umann015b0592018-08-13 18:43:08 +000083/// Note that this class is immutable (essentially a wrapper around an
84/// ImmutableList), and new elements can only be added by creating new
85/// FieldChainInfo objects through add().
Kristof Umann56963ae2018-08-13 18:17:05 +000086class FieldChainInfo {
87public:
Kristof Umann015b0592018-08-13 18:43:08 +000088 using FieldChainImpl = llvm::ImmutableListImpl<const FieldNode &>;
89 using FieldChain = llvm::ImmutableList<const FieldNode &>;
Kristof Umann56963ae2018-08-13 18:17:05 +000090
91private:
Kristof Umann015b0592018-08-13 18:43:08 +000092 FieldChain::Factory &ChainFactory;
Kristof Umann56963ae2018-08-13 18:17:05 +000093 FieldChain Chain;
94
Kristof Umann56963ae2018-08-13 18:17:05 +000095public:
96 FieldChainInfo() = delete;
Kristof Umann015b0592018-08-13 18:43:08 +000097 FieldChainInfo(FieldChain::Factory &F) : ChainFactory(F) {}
98 FieldChainInfo(const FieldChainInfo &Other) = default;
Kristof Umann56963ae2018-08-13 18:17:05 +000099
Kristof Umann015b0592018-08-13 18:43:08 +0000100 template <class FieldNodeT> FieldChainInfo add(const FieldNodeT &FN);
Kristof Umann56963ae2018-08-13 18:17:05 +0000101
Kristof Umann015b0592018-08-13 18:43:08 +0000102 bool contains(const FieldRegion *FR) const;
103 const FieldRegion *getUninitRegion() const;
104 void printNoteMsg(llvm::raw_ostream &Out) const;
Kristof Umann56963ae2018-08-13 18:17:05 +0000105};
106
Kristof Umann015b0592018-08-13 18:43:08 +0000107using UninitFieldMap = std::map<const FieldRegion *, llvm::SmallString<50>>;
Kristof Umann56963ae2018-08-13 18:17:05 +0000108
109/// Searches for and stores uninitialized fields in a non-union object.
110class FindUninitializedFields {
111 ProgramStateRef State;
112 const TypedValueRegion *const ObjectR;
113
114 const bool IsPedantic;
115 const bool CheckPointeeInitialization;
116
117 bool IsAnyFieldInitialized = false;
118
Kristof Umann015b0592018-08-13 18:43:08 +0000119 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;
Kristof Umann56963ae2018-08-13 18:17:05 +0000132
133public:
134 FindUninitializedFields(ProgramStateRef State,
135 const TypedValueRegion *const R, bool IsPedantic,
136 bool CheckPointeeInitialization);
Kristof Umann015b0592018-08-13 18:43:08 +0000137 const UninitFieldMap &getUninitFields();
Kristof Umann56963ae2018-08-13 18:17:05 +0000138
139private:
Kristof Umann56963ae2018-08-13 18:17:05 +0000140 // For the purposes of this checker, we'll regard the object under checking as
141 // a directed tree, where
142 // * the root is the object under checking
143 // * every node is an object that is
144 // - a union
145 // - a non-union record
146 // - a pointer/reference
147 // - an array
148 // - of a primitive type, which we'll define later in a helper function.
149 // * the parent of each node is the object that contains it
150 // * every leaf is an array, a primitive object, a nullptr or an undefined
151 // pointer.
152 //
153 // Example:
154 //
155 // struct A {
156 // struct B {
157 // int x, y = 0;
158 // };
159 // B b;
160 // int *iptr = new int;
161 // B* bptr;
162 //
163 // A() {}
164 // };
165 //
166 // The directed tree:
167 //
168 // ->x
169 // /
170 // ->b--->y
171 // /
172 // A-->iptr->(int value)
173 // \
174 // ->bptr
175 //
176 // From this we'll construct a vector of fieldchains, where each fieldchain
177 // represents an uninitialized field. An uninitialized field may be a
178 // primitive object, a pointer, a pointee or a union without a single
179 // initialized field.
180 // In the above example, for the default constructor call we'll end up with
181 // these fieldchains:
182 //
183 // this->b.x
184 // this->iptr (pointee uninit)
185 // this->bptr (pointer uninit)
186 //
187 // We'll traverse each node of the above graph with the appropiate one of
188 // these methods:
189
190 /// This method checks a region of a union object, and returns true if no
191 /// field is initialized within the region.
192 bool isUnionUninit(const TypedValueRegion *R);
193
194 /// This method checks a region of a non-union object, and returns true if
195 /// an uninitialized field is found within the region.
196 bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
197
198 /// This method checks a region of a pointer or reference object, and returns
199 /// true if the ptr/ref object itself or any field within the pointee's region
200 /// is uninitialized.
201 bool isPointerOrReferenceUninit(const FieldRegion *FR,
202 FieldChainInfo LocalChain);
203
204 /// This method returns true if the value of a primitive object is
205 /// uninitialized.
206 bool isPrimitiveUninit(const SVal &V);
207
208 // Note that we don't have a method for arrays -- the elements of an array are
209 // often left uninitialized intentionally even when it is of a C++ record
210 // type, so we'll assume that an array is always initialized.
211 // TODO: Add a support for nonloc::LocAsInteger.
Kristof Umann015b0592018-08-13 18:43:08 +0000212
213 /// Processes LocalChain and attempts to insert it into UninitFields. Returns
214 /// true on success.
215 ///
216 /// Since this class analyzes regions with recursion, we'll only store
217 /// references to temporary FieldNode objects created on the stack. This means
218 /// that after analyzing a leaf of the directed tree described above, the
219 /// elements LocalChain references will be destructed, so we can't store it
220 /// directly.
221 bool addFieldToUninits(FieldChainInfo LocalChain);
Kristof Umann56963ae2018-08-13 18:17:05 +0000222};
223
224/// Returns true if T is a primitive type. We defined this type so that for
225/// objects that we'd only like analyze as much as checking whether their
226/// value is undefined or not, such as ints and doubles, can be analyzed with
227/// ease. This also helps ensuring that every special field type is handled
228/// correctly.
229static bool isPrimitiveType(const QualType &T) {
230 return T->isBuiltinType() || T->isEnumeralType() || T->isMemberPointerType();
231}
232
Kristof Umann015b0592018-08-13 18:43:08 +0000233// Template method definitions.
234
235template <class FieldNodeT>
236inline FieldChainInfo FieldChainInfo::add(const FieldNodeT &FN) {
237 assert(!contains(FN.getRegion()) &&
238 "Can't add a field that is already a part of the "
239 "fieldchain! Is this a cyclic reference?");
240
241 FieldChainInfo NewChain = *this;
242 NewChain.Chain = ChainFactory.add(FN, Chain);
243 return NewChain;
244}
245
Kristof Umann56963ae2018-08-13 18:17:05 +0000246} // end of namespace ento
247} // end of namespace clang
248
249#endif // LLVM_CLANG_STATICANALYZER_UNINITIALIZEDOBJECT_H