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:
LocField(const FieldRegion * FR,const bool IsDereferenced=true)34 LocField(const FieldRegion *FR, const bool IsDereferenced = true)
35 : FieldNode(FR), IsDereferenced(IsDereferenced) {}
36
printNoteMsg(llvm::raw_ostream & Out) const37 void printNoteMsg(llvm::raw_ostream &Out) const override {
38 if (IsDereferenced)
39 Out << "uninitialized pointee ";
40 else
41 Out << "uninitialized pointer ";
42 }
43
printPrefix(llvm::raw_ostream & Out) const44 void printPrefix(llvm::raw_ostream &Out) const override {}
45
printNode(llvm::raw_ostream & Out) const46 void printNode(llvm::raw_ostream &Out) const override {
47 Out << getVariableName(getDecl());
48 }
49
printSeparator(llvm::raw_ostream & Out) const50 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:
NeedsCastLocField(const FieldRegion * FR,const QualType & T)64 NeedsCastLocField(const FieldRegion *FR, const QualType &T)
65 : FieldNode(FR), CastBackType(T) {}
66
printNoteMsg(llvm::raw_ostream & Out) const67 void printNoteMsg(llvm::raw_ostream &Out) const override {
68 Out << "uninitialized pointee ";
69 }
70
printPrefix(llvm::raw_ostream & Out) const71 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
printNode(llvm::raw_ostream & Out) const81 void printNode(llvm::raw_ostream &Out) const override {
82 Out << getVariableName(getDecl()) << ')';
83 }
84
printSeparator(llvm::raw_ostream & Out) const85 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:
CyclicLocField(const FieldRegion * FR)92 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
93
printNoteMsg(llvm::raw_ostream & Out) const94 void printNoteMsg(llvm::raw_ostream &Out) const override {
95 Out << "object references itself ";
96 }
97
printPrefix(llvm::raw_ostream & Out) const98 void printPrefix(llvm::raw_ostream &Out) const override {}
99
printNode(llvm::raw_ostream & Out) const100 void printNode(llvm::raw_ostream &Out) const override {
101 Out << getVariableName(getDecl());
102 }
103
printSeparator(llvm::raw_ostream & Out) const104 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;
DereferenceInfoDereferenceInfo118 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
isDereferencableUninit(const FieldRegion * FR,FieldChainInfo LocalChain)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
dereference(ProgramStateRef State,const FieldRegion * FR)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
isVoidPointer(QualType T)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