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