blob: 07751a92360346592edf6a5af37306f2d24b2115 [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
Kristof Umann56963ae2018-08-13 18:17:05 +0000114 const bool CheckPointeeInitialization;
Kristof Umann56963ae2018-08-13 18:17:05 +0000115 bool IsAnyFieldInitialized = false;
116
Kristof Umann015b0592018-08-13 18:43:08 +0000117 FieldChainInfo::FieldChain::Factory ChainFactory;
118
119 /// A map for assigning uninitialized regions to note messages. For example,
120 ///
121 /// struct A {
122 /// int x;
123 /// };
124 ///
125 /// A a;
126 ///
127 /// After analyzing `a`, the map will contain a pair for `a.x`'s region and
128 /// the note message "uninitialized field 'this->x'.
129 UninitFieldMap UninitFields;
Kristof Umann56963ae2018-08-13 18:17:05 +0000130
131public:
Kristof Umann23ca9662018-08-13 18:48:34 +0000132 /// Constructs the FindUninitializedField object, searches for and stores
133 /// uninitialized fields in R.
Kristof Umann56963ae2018-08-13 18:17:05 +0000134 FindUninitializedFields(ProgramStateRef State,
Kristof Umann23ca9662018-08-13 18:48:34 +0000135 const TypedValueRegion *const R,
Kristof Umann56963ae2018-08-13 18:17:05 +0000136 bool CheckPointeeInitialization);
Kristof Umann23ca9662018-08-13 18:48:34 +0000137
138 const UninitFieldMap &getUninitFields() { return UninitFields; }
139
140 /// Returns whether the analyzed region contains at least one initialized
141 /// field.
142 bool isAnyFieldInitialized() { return IsAnyFieldInitialized; }
Kristof Umann56963ae2018-08-13 18:17:05 +0000143
144private:
Kristof Umann56963ae2018-08-13 18:17:05 +0000145 // For the purposes of this checker, we'll regard the object under checking as
146 // a directed tree, where
147 // * the root is the object under checking
148 // * every node is an object that is
149 // - a union
150 // - a non-union record
151 // - a pointer/reference
152 // - an array
153 // - of a primitive type, which we'll define later in a helper function.
154 // * the parent of each node is the object that contains it
155 // * every leaf is an array, a primitive object, a nullptr or an undefined
156 // pointer.
157 //
158 // Example:
159 //
160 // struct A {
161 // struct B {
162 // int x, y = 0;
163 // };
164 // B b;
165 // int *iptr = new int;
166 // B* bptr;
167 //
168 // A() {}
169 // };
170 //
171 // The directed tree:
172 //
173 // ->x
174 // /
175 // ->b--->y
176 // /
177 // A-->iptr->(int value)
178 // \
179 // ->bptr
180 //
181 // From this we'll construct a vector of fieldchains, where each fieldchain
182 // represents an uninitialized field. An uninitialized field may be a
183 // primitive object, a pointer, a pointee or a union without a single
184 // initialized field.
185 // In the above example, for the default constructor call we'll end up with
186 // these fieldchains:
187 //
188 // this->b.x
189 // this->iptr (pointee uninit)
190 // this->bptr (pointer uninit)
191 //
192 // We'll traverse each node of the above graph with the appropiate one of
193 // these methods:
194
195 /// This method checks a region of a union object, and returns true if no
196 /// field is initialized within the region.
197 bool isUnionUninit(const TypedValueRegion *R);
198
199 /// This method checks a region of a non-union object, and returns true if
200 /// an uninitialized field is found within the region.
201 bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
202
203 /// This method checks a region of a pointer or reference object, and returns
204 /// true if the ptr/ref object itself or any field within the pointee's region
205 /// is uninitialized.
206 bool isPointerOrReferenceUninit(const FieldRegion *FR,
207 FieldChainInfo LocalChain);
208
209 /// This method returns true if the value of a primitive object is
210 /// uninitialized.
211 bool isPrimitiveUninit(const SVal &V);
212
213 // Note that we don't have a method for arrays -- the elements of an array are
214 // often left uninitialized intentionally even when it is of a C++ record
215 // type, so we'll assume that an array is always initialized.
216 // TODO: Add a support for nonloc::LocAsInteger.
Kristof Umann015b0592018-08-13 18:43:08 +0000217
218 /// Processes LocalChain and attempts to insert it into UninitFields. Returns
219 /// true on success.
220 ///
221 /// Since this class analyzes regions with recursion, we'll only store
222 /// references to temporary FieldNode objects created on the stack. This means
223 /// that after analyzing a leaf of the directed tree described above, the
224 /// elements LocalChain references will be destructed, so we can't store it
225 /// directly.
226 bool addFieldToUninits(FieldChainInfo LocalChain);
Kristof Umann56963ae2018-08-13 18:17:05 +0000227};
228
229/// Returns true if T is a primitive type. We defined this type so that for
230/// objects that we'd only like analyze as much as checking whether their
231/// value is undefined or not, such as ints and doubles, can be analyzed with
232/// ease. This also helps ensuring that every special field type is handled
233/// correctly.
234static bool isPrimitiveType(const QualType &T) {
235 return T->isBuiltinType() || T->isEnumeralType() || T->isMemberPointerType();
236}
237
Kristof Umann015b0592018-08-13 18:43:08 +0000238// Template method definitions.
239
240template <class FieldNodeT>
241inline FieldChainInfo FieldChainInfo::add(const FieldNodeT &FN) {
242 assert(!contains(FN.getRegion()) &&
243 "Can't add a field that is already a part of the "
244 "fieldchain! Is this a cyclic reference?");
245
246 FieldChainInfo NewChain = *this;
247 NewChain.Chain = ChainFactory.add(FN, Chain);
248 return NewChain;
249}
250
Kristof Umann56963ae2018-08-13 18:17:05 +0000251} // end of namespace ento
252} // end of namespace clang
253
254#endif // LLVM_CLANG_STATICANALYZER_UNINITIALIZEDOBJECT_H