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