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