]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / UninitializedObject / UninitializedPointee.cpp
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 "UninitializedObject.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
23
24 using namespace clang;
25 using namespace clang::ento;
26
27 namespace {
28
29 /// Represents a pointer or a reference field.
30 class LocField final : public FieldNode {
31   /// We'll store whether the pointee or the pointer itself is uninitialited.
32   const bool IsDereferenced;
33
34 public:
35   LocField(const FieldRegion *FR, const bool IsDereferenced = true)
36       : FieldNode(FR), IsDereferenced(IsDereferenced) {}
37
38   virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
39     if (IsDereferenced)
40       Out << "uninitialized pointee ";
41     else
42       Out << "uninitialized pointer ";
43   }
44
45   virtual void printPrefix(llvm::raw_ostream &Out) const override {}
46
47   virtual void printNode(llvm::raw_ostream &Out) const override {
48     Out << getVariableName(getDecl());
49   }
50
51   virtual void printSeparator(llvm::raw_ostream &Out) const override {
52     if (getDecl()->getType()->isPointerType())
53       Out << "->";
54     else
55       Out << '.';
56   }
57 };
58
59 /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
60 /// needs to be casted back to its dynamic type for a correct note message.
61 class NeedsCastLocField final : public FieldNode {
62   QualType CastBackType;
63
64 public:
65   NeedsCastLocField(const FieldRegion *FR, const QualType &T)
66       : FieldNode(FR), CastBackType(T) {}
67
68   virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
69     Out << "uninitialized pointee ";
70   }
71
72   virtual void printPrefix(llvm::raw_ostream &Out) const override {
73     // If this object is a nonloc::LocAsInteger.
74     if (getDecl()->getType()->isIntegerType())
75       Out << "reinterpret_cast";
76     // If this pointer's dynamic type is different then it's static type.
77     else
78       Out << "static_cast";
79     Out << '<' << CastBackType.getAsString() << ">(";
80   }
81
82   virtual void printNode(llvm::raw_ostream &Out) const override {
83     Out << getVariableName(getDecl()) << ')';
84   }
85
86   virtual void printSeparator(llvm::raw_ostream &Out) const override {
87     Out << "->";
88   }
89 };
90
91 /// Represents a Loc field that points to itself.
92 class CyclicLocField final : public FieldNode {
93
94 public:
95   CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
96
97   virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
98     Out << "object references itself ";
99   }
100
101   virtual void printPrefix(llvm::raw_ostream &Out) const override {}
102
103   virtual void printNode(llvm::raw_ostream &Out) const override {
104     Out << getVariableName(getDecl());
105   }
106
107   virtual void printSeparator(llvm::raw_ostream &Out) const override {
108     llvm_unreachable("CyclicLocField objects must be the last node of the "
109                      "fieldchain!");
110   }
111 };
112
113 } // end of anonymous namespace
114
115 // Utility function declarations.
116
117 struct DereferenceInfo {
118   const TypedValueRegion *R;
119   const bool NeedsCastBack;
120   const bool IsCyclic;
121   DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
122       : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
123 };
124
125 /// Dereferences \p FR and returns with the pointee's region, and whether it
126 /// needs to be casted back to it's location type. If for whatever reason
127 /// dereferencing fails, returns with None.
128 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
129                                                    const FieldRegion *FR);
130
131 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
132 /// type (void*, void**, ...).
133 static bool isVoidPointer(QualType T);
134
135 //===----------------------------------------------------------------------===//
136 //                   Methods for FindUninitializedFields.
137 //===----------------------------------------------------------------------===//
138
139 bool FindUninitializedFields::isDereferencableUninit(
140     const FieldRegion *FR, FieldChainInfo LocalChain) {
141
142   SVal V = State->getSVal(FR);
143
144   assert((isDereferencableType(FR->getDecl()->getType()) ||
145           V.getAs<nonloc::LocAsInteger>()) &&
146          "This method only checks dereferenceable objects!");
147
148   if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
149     IsAnyFieldInitialized = true;
150     return false;
151   }
152
153   if (V.isUndef()) {
154     return addFieldToUninits(
155         LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
156   }
157
158   if (!Opts.CheckPointeeInitialization) {
159     IsAnyFieldInitialized = true;
160     return false;
161   }
162
163   // At this point the pointer itself is initialized and points to a valid
164   // location, we'll now check the pointee.
165   llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
166   if (!DerefInfo) {
167     IsAnyFieldInitialized = true;
168     return false;
169   }
170
171   if (DerefInfo->IsCyclic)
172     return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
173
174   const TypedValueRegion *R = DerefInfo->R;
175   const bool NeedsCastBack = DerefInfo->NeedsCastBack;
176
177   QualType DynT = R->getLocationType();
178   QualType PointeeT = DynT->getPointeeType();
179
180   if (PointeeT->isStructureOrClassType()) {
181     if (NeedsCastBack)
182       return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
183     return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
184   }
185
186   if (PointeeT->isUnionType()) {
187     if (isUnionUninit(R)) {
188       if (NeedsCastBack)
189         return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
190                                  R);
191       return addFieldToUninits(LocalChain.add(LocField(FR)), R);
192     } else {
193       IsAnyFieldInitialized = true;
194       return false;
195     }
196   }
197
198   if (PointeeT->isArrayType()) {
199     IsAnyFieldInitialized = true;
200     return false;
201   }
202
203   assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
204          "At this point FR must either have a primitive dynamic type, or it "
205          "must be a null, undefined, unknown or concrete pointer!");
206
207   SVal PointeeV = State->getSVal(R);
208
209   if (isPrimitiveUninit(PointeeV)) {
210     if (NeedsCastBack)
211       return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
212     return addFieldToUninits(LocalChain.add(LocField(FR)), R);
213   }
214
215   IsAnyFieldInitialized = true;
216   return false;
217 }
218
219 //===----------------------------------------------------------------------===//
220 //                           Utility functions.
221 //===----------------------------------------------------------------------===//
222
223 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
224                                                    const FieldRegion *FR) {
225
226   llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
227
228   SVal V = State->getSVal(FR);
229   assert(V.getAsRegion() && "V must have an underlying region!");
230
231   // If the static type of the field is a void pointer, or it is a
232   // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
233   // dereferencing.
234   bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
235                        V.getAs<nonloc::LocAsInteger>();
236
237   // The region we'd like to acquire.
238   const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
239   if (!R)
240     return None;
241
242   VisitedRegions.insert(R);
243
244   // We acquire the dynamic type of R,
245   QualType DynT = R->getLocationType();
246
247   while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
248
249     R = Tmp->getAs<TypedValueRegion>();
250     if (!R)
251       return None;
252
253     // We found a cyclic pointer, like int *ptr = (int *)&ptr.
254     if (!VisitedRegions.insert(R).second)
255       return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
256
257     DynT = R->getLocationType();
258     // In order to ensure that this loop terminates, we're also checking the
259     // dynamic type of R, since type hierarchy is finite.
260     if (isDereferencableType(DynT->getPointeeType()))
261       break;
262   }
263
264   while (R->getAs<CXXBaseObjectRegion>()) {
265     NeedsCastBack = true;
266
267     if (!isa<TypedValueRegion>(R->getSuperRegion()))
268       break;
269     R = R->getSuperRegion()->getAs<TypedValueRegion>();
270   }
271
272   return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
273 }
274
275 static bool isVoidPointer(QualType T) {
276   while (!T.isNull()) {
277     if (T->isVoidPointerType())
278       return true;
279     T = T->getPointeeType();
280   }
281   return false;
282 }