blob: aead59c7bf87ca1f65b6959d6258459229939b2c [file] [log] [blame]
Kristof Umannceb5f652018-09-14 09:07:40 +00001//===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
Kristof Umann56963ae2018-08-13 18:17:05 +00002//
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//
Kristof Umann6cec6c42018-09-14 09:39:26 +000013// To read about command line options and documentation about how the checker
14// works, refer to UninitializedObjectChecker.h.
Kristof Umann56963ae2018-08-13 18:17:05 +000015//
16//===----------------------------------------------------------------------===//
17
Kristof Umanna37bba42018-08-13 18:22:22 +000018#include "UninitializedObject.h"
Kristof Umann56963ae2018-08-13 18:17:05 +000019#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20#include "clang/StaticAnalyzer/Core/Checker.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
23
24using namespace clang;
25using namespace clang::ento;
26
Kristof Umann015b0592018-08-13 18:43:08 +000027namespace {
28
29/// Represents a pointer or a reference field.
Richard Smith651d6832018-08-13 22:07:11 +000030class LocField final : public FieldNode {
Kristof Umann015b0592018-08-13 18:43:08 +000031 /// We'll store whether the pointee or the pointer itself is uninitialited.
32 const bool IsDereferenced;
33
34public:
35 LocField(const FieldRegion *FR, const bool IsDereferenced = true)
36 : FieldNode(FR), IsDereferenced(IsDereferenced) {}
37
38 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
39 if (IsDereferenced)
40 Out << "uninitialized pointee ";
41 else
42 Out << "uninitialized pointer ";
43 }
44
45 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
46
47 virtual void printNode(llvm::raw_ostream &Out) const override {
48 Out << getVariableName(getDecl());
49 }
50
51 virtual void printSeparator(llvm::raw_ostream &Out) const override {
52 if (getDecl()->getType()->isPointerType())
53 Out << "->";
54 else
55 Out << '.';
56 }
57};
58
Kristof Umannf0513792018-09-14 10:18:26 +000059/// 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.
Ilya Biryukov88ad9cf2018-09-14 11:28:48 +000061class NeedsCastLocField final : public FieldNode {
Kristof Umann5a424412018-08-14 08:20:51 +000062 QualType CastBackType;
63
64public:
65 NeedsCastLocField(const FieldRegion *FR, const QualType &T)
66 : FieldNode(FR), CastBackType(T) {}
67
68 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
69 Out << "uninitialized pointee ";
70 }
71
72 virtual void printPrefix(llvm::raw_ostream &Out) const override {
Kristof Umannf0513792018-09-14 10:18:26 +000073 // 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() << ">(";
Kristof Umann5a424412018-08-14 08:20:51 +000080 }
81
82 virtual void printNode(llvm::raw_ostream &Out) const override {
83 Out << getVariableName(getDecl()) << ')';
84 }
85
86 virtual void printSeparator(llvm::raw_ostream &Out) const override {
87 Out << "->";
88 }
89};
90
Kristof Umann8e5328b2018-10-11 11:58:53 +000091/// Represents a Loc field that points to itself.
92class CyclicLocField final : public FieldNode {
93
94public:
95 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
96
97 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
98 Out << "object references itself ";
99 }
100
101 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
102
103 virtual void printNode(llvm::raw_ostream &Out) const override {
104 Out << getVariableName(getDecl());
105 }
106
107 virtual void printSeparator(llvm::raw_ostream &Out) const override {
108 llvm_unreachable("CyclicLocField objects must be the last node of the "
109 "fieldchain!");
110 }
111};
112
Kristof Umann015b0592018-08-13 18:43:08 +0000113} // end of anonymous namespace
114
Kristof Umann56963ae2018-08-13 18:17:05 +0000115// Utility function declarations.
116
Kristof Umann8e5328b2018-10-11 11:58:53 +0000117struct DereferenceInfo {
118 const TypedValueRegion *R;
119 const bool NeedsCastBack;
120 const bool IsCyclic;
121 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
122 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
123};
Kristof Umannf0dd1012018-09-14 08:58:21 +0000124
125/// Dereferences \p FR and returns with the pointee's region, and whether it
126/// needs to be casted back to it's location type. If for whatever reason
127/// dereferencing fails, returns with None.
128static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
129 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000130
Kristof Umann8e5328b2018-10-11 11:58:53 +0000131/// Returns whether \p T can be (transitively) dereferenced to a void pointer
132/// type (void*, void**, ...).
133static bool isVoidPointer(QualType T);
134
Kristof Umann56963ae2018-08-13 18:17:05 +0000135//===----------------------------------------------------------------------===//
136// Methods for FindUninitializedFields.
137//===----------------------------------------------------------------------===//
138
Kristof Umannceb5f652018-09-14 09:07:40 +0000139bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000140 const FieldRegion *FR, FieldChainInfo LocalChain) {
141
Kristof Umann56963ae2018-08-13 18:17:05 +0000142 SVal V = State->getSVal(FR);
143
Kristof Umannf0513792018-09-14 10:18:26 +0000144 assert((isDereferencableType(FR->getDecl()->getType()) ||
145 V.getAs<nonloc::LocAsInteger>()) &&
Raphael Isemannb23ccec2018-12-10 12:37:46 +0000146 "This method only checks dereferenceable objects!");
Kristof Umannf0513792018-09-14 10:18:26 +0000147
Kristof Umann56963ae2018-08-13 18:17:05 +0000148 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
149 IsAnyFieldInitialized = true;
150 return false;
151 }
152
153 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000154 return addFieldToUninits(
Kristof Umann4ff77692018-11-18 11:34:10 +0000155 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
Kristof Umann56963ae2018-08-13 18:17:05 +0000156 }
157
Kristof Umann6cec6c42018-09-14 09:39:26 +0000158 if (!Opts.CheckPointeeInitialization) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000159 IsAnyFieldInitialized = true;
160 return false;
161 }
162
Kristof Umann56963ae2018-08-13 18:17:05 +0000163 // At this point the pointer itself is initialized and points to a valid
164 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000165 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000166 if (!DerefInfo) {
167 IsAnyFieldInitialized = true;
168 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000169 }
170
Kristof Umann8e5328b2018-10-11 11:58:53 +0000171 if (DerefInfo->IsCyclic)
Kristof Umann4ff77692018-11-18 11:34:10 +0000172 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
Kristof Umann8e5328b2018-10-11 11:58:53 +0000173
174 const TypedValueRegion *R = DerefInfo->R;
175 const bool NeedsCastBack = DerefInfo->NeedsCastBack;
Kristof Umann64601962018-08-21 10:45:21 +0000176
Kristof Umannf0dd1012018-09-14 08:58:21 +0000177 QualType DynT = R->getLocationType();
178 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000179
Kristof Umannf0dd1012018-09-14 08:58:21 +0000180 if (PointeeT->isStructureOrClassType()) {
181 if (NeedsCastBack)
182 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
183 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
184 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000185
Kristof Umannf0dd1012018-09-14 08:58:21 +0000186 if (PointeeT->isUnionType()) {
187 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000188 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000189 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
190 R);
191 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000192 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000193 IsAnyFieldInitialized = true;
194 return false;
195 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000196 }
197
Kristof Umannf0dd1012018-09-14 08:58:21 +0000198 if (PointeeT->isArrayType()) {
199 IsAnyFieldInitialized = true;
200 return false;
201 }
202
203 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000204 "At this point FR must either have a primitive dynamic type, or it "
205 "must be a null, undefined, unknown or concrete pointer!");
206
Kristof Umannf0dd1012018-09-14 08:58:21 +0000207 SVal PointeeV = State->getSVal(R);
208
209 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000210 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000211 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
212 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umann5a424412018-08-14 08:20:51 +0000213 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000214
215 IsAnyFieldInitialized = true;
216 return false;
217}
218
219//===----------------------------------------------------------------------===//
220// Utility functions.
221//===----------------------------------------------------------------------===//
222
Kristof Umannf0dd1012018-09-14 08:58:21 +0000223static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
224 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000225
Kristof Umannf0dd1012018-09-14 08:58:21 +0000226 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000227
Kristof Umann64601962018-08-21 10:45:21 +0000228 SVal V = State->getSVal(FR);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000229 assert(V.getAsRegion() && "V must have an underlying region!");
Kristof Umann64601962018-08-21 10:45:21 +0000230
Kristof Umannf0513792018-09-14 10:18:26 +0000231 // If the static type of the field is a void pointer, or it is a
232 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
233 // dereferencing.
234 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
235 V.getAs<nonloc::LocAsInteger>();
236
Kristof Umannf0dd1012018-09-14 08:58:21 +0000237 // The region we'd like to acquire.
238 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
239 if (!R)
240 return None;
241
242 VisitedRegions.insert(R);
243
244 // We acquire the dynamic type of R,
245 QualType DynT = R->getLocationType();
246
247 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
248
249 R = Tmp->getAs<TypedValueRegion>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000250 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000251 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000252
Kristof Umannf0dd1012018-09-14 08:58:21 +0000253 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000254 if (!VisitedRegions.insert(R).second)
Kristof Umann8e5328b2018-10-11 11:58:53 +0000255 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
Kristof Umann64601962018-08-21 10:45:21 +0000256
Kristof Umannf0dd1012018-09-14 08:58:21 +0000257 DynT = R->getLocationType();
258 // In order to ensure that this loop terminates, we're also checking the
259 // dynamic type of R, since type hierarchy is finite.
260 if (isDereferencableType(DynT->getPointeeType()))
261 break;
Kristof Umann64601962018-08-21 10:45:21 +0000262 }
263
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000264 while (R->getAs<CXXBaseObjectRegion>()) {
265 NeedsCastBack = true;
266
267 if (!isa<TypedValueRegion>(R->getSuperRegion()))
268 break;
269 R = R->getSuperRegion()->getAs<TypedValueRegion>();
270 }
271
Kristof Umann8e5328b2018-10-11 11:58:53 +0000272 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
273}
274
275static bool isVoidPointer(QualType T) {
276 while (!T.isNull()) {
277 if (T->isVoidPointerType())
278 return true;
279 T = T->getPointeeType();
280 }
281 return false;
Kristof Umann64601962018-08-21 10:45:21 +0000282}