blob: 23e1b204be41df02db5f3d298b42877ad1c1f4e1 [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
Richard Smith651d6832018-08-13 22:07:11 +000018#include "../ClangSACheckers.h"
Kristof Umanna37bba42018-08-13 18:22:22 +000019#include "UninitializedObject.h"
Kristof Umann56963ae2018-08-13 18:17:05 +000020#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
25using namespace clang;
26using namespace clang::ento;
27
Kristof Umann015b0592018-08-13 18:43:08 +000028namespace {
29
30/// Represents a pointer or a reference field.
Richard Smith651d6832018-08-13 22:07:11 +000031class LocField final : public FieldNode {
Kristof Umann015b0592018-08-13 18:43:08 +000032 /// We'll store whether the pointee or the pointer itself is uninitialited.
33 const bool IsDereferenced;
34
35public:
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
Kristof Umannf0513792018-09-14 10:18:26 +000060/// 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.
Ilya Biryukov88ad9cf2018-09-14 11:28:48 +000062class NeedsCastLocField final : public FieldNode {
Kristof Umann5a424412018-08-14 08:20:51 +000063 QualType CastBackType;
64
65public:
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 {
Kristof Umannf0513792018-09-14 10:18:26 +000074 // 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() << ">(";
Kristof Umann5a424412018-08-14 08:20:51 +000081 }
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
Kristof Umann8e5328b2018-10-11 11:58:53 +000092/// Represents a Loc field that points to itself.
93class CyclicLocField final : public FieldNode {
94
95public:
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
Kristof Umann015b0592018-08-13 18:43:08 +0000114} // end of anonymous namespace
115
Kristof Umann56963ae2018-08-13 18:17:05 +0000116// Utility function declarations.
117
Kristof Umann8e5328b2018-10-11 11:58:53 +0000118struct 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};
Kristof Umannf0dd1012018-09-14 08:58:21 +0000125
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.
129static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
130 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000131
Kristof Umann8e5328b2018-10-11 11:58:53 +0000132/// Returns whether \p T can be (transitively) dereferenced to a void pointer
133/// type (void*, void**, ...).
134static bool isVoidPointer(QualType T);
135
Kristof Umann56963ae2018-08-13 18:17:05 +0000136//===----------------------------------------------------------------------===//
137// Methods for FindUninitializedFields.
138//===----------------------------------------------------------------------===//
139
Kristof Umannceb5f652018-09-14 09:07:40 +0000140bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000141 const FieldRegion *FR, FieldChainInfo LocalChain) {
142
Kristof Umann56963ae2018-08-13 18:17:05 +0000143 SVal V = State->getSVal(FR);
144
Kristof Umannf0513792018-09-14 10:18:26 +0000145 assert((isDereferencableType(FR->getDecl()->getType()) ||
146 V.getAs<nonloc::LocAsInteger>()) &&
147 "This method only checks dereferencable objects!");
148
Kristof Umann56963ae2018-08-13 18:17:05 +0000149 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
150 IsAnyFieldInitialized = true;
151 return false;
152 }
153
154 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000155 return addFieldToUninits(
Kristof Umann4ff77692018-11-18 11:34:10 +0000156 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
Kristof Umann56963ae2018-08-13 18:17:05 +0000157 }
158
Kristof Umann6cec6c42018-09-14 09:39:26 +0000159 if (!Opts.CheckPointeeInitialization) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000160 IsAnyFieldInitialized = true;
161 return false;
162 }
163
Kristof Umann56963ae2018-08-13 18:17:05 +0000164 // At this point the pointer itself is initialized and points to a valid
165 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000166 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000167 if (!DerefInfo) {
168 IsAnyFieldInitialized = true;
169 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000170 }
171
Kristof Umann8e5328b2018-10-11 11:58:53 +0000172 if (DerefInfo->IsCyclic)
Kristof Umann4ff77692018-11-18 11:34:10 +0000173 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
Kristof Umann8e5328b2018-10-11 11:58:53 +0000174
175 const TypedValueRegion *R = DerefInfo->R;
176 const bool NeedsCastBack = DerefInfo->NeedsCastBack;
Kristof Umann64601962018-08-21 10:45:21 +0000177
Kristof Umannf0dd1012018-09-14 08:58:21 +0000178 QualType DynT = R->getLocationType();
179 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000180
Kristof Umannf0dd1012018-09-14 08:58:21 +0000181 if (PointeeT->isStructureOrClassType()) {
182 if (NeedsCastBack)
183 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
184 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
185 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000186
Kristof Umannf0dd1012018-09-14 08:58:21 +0000187 if (PointeeT->isUnionType()) {
188 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000189 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000190 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
191 R);
192 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000193 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000194 IsAnyFieldInitialized = true;
195 return false;
196 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000197 }
198
Kristof Umannf0dd1012018-09-14 08:58:21 +0000199 if (PointeeT->isArrayType()) {
200 IsAnyFieldInitialized = true;
201 return false;
202 }
203
204 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000205 "At this point FR must either have a primitive dynamic type, or it "
206 "must be a null, undefined, unknown or concrete pointer!");
207
Kristof Umannf0dd1012018-09-14 08:58:21 +0000208 SVal PointeeV = State->getSVal(R);
209
210 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000211 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000212 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
213 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umann5a424412018-08-14 08:20:51 +0000214 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000215
216 IsAnyFieldInitialized = true;
217 return false;
218}
219
220//===----------------------------------------------------------------------===//
221// Utility functions.
222//===----------------------------------------------------------------------===//
223
Kristof Umannf0dd1012018-09-14 08:58:21 +0000224static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
225 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000226
Kristof Umannf0dd1012018-09-14 08:58:21 +0000227 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000228
Kristof Umann64601962018-08-21 10:45:21 +0000229 SVal V = State->getSVal(FR);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000230 assert(V.getAsRegion() && "V must have an underlying region!");
Kristof Umann64601962018-08-21 10:45:21 +0000231
Kristof Umannf0513792018-09-14 10:18:26 +0000232 // 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
Kristof Umannf0dd1012018-09-14 08:58:21 +0000238 // 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>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000251 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000252 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000253
Kristof Umannf0dd1012018-09-14 08:58:21 +0000254 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000255 if (!VisitedRegions.insert(R).second)
Kristof Umann8e5328b2018-10-11 11:58:53 +0000256 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
Kristof Umann64601962018-08-21 10:45:21 +0000257
Kristof Umannf0dd1012018-09-14 08:58:21 +0000258 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;
Kristof Umann64601962018-08-21 10:45:21 +0000263 }
264
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000265 while (R->getAs<CXXBaseObjectRegion>()) {
266 NeedsCastBack = true;
267
268 if (!isa<TypedValueRegion>(R->getSuperRegion()))
269 break;
270 R = R->getSuperRegion()->getAs<TypedValueRegion>();
271 }
272
Kristof Umann8e5328b2018-10-11 11:58:53 +0000273 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
274}
275
276static bool isVoidPointer(QualType T) {
277 while (!T.isNull()) {
278 if (T->isVoidPointerType())
279 return true;
280 T = T->getPointeeType();
281 }
282 return false;
Kristof Umann64601962018-08-21 10:45:21 +0000283}