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