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