blob: f0dd0bf813affb7a9d73f54da3651ab27d26bbf0 [file] [log] [blame]
Kristof Umannceb5f652018-09-14 09:07:40 +00001//===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
Kristof Umann56963ae2018-08-13 18:17:05 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Kristof Umann56963ae2018-08-13 18:17:05 +00006//
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//
Kristof Umann6cec6c42018-09-14 09:39:26 +000012// To read about command line options and documentation about how the checker
13// works, refer to UninitializedObjectChecker.h.
Kristof Umann56963ae2018-08-13 18:17:05 +000014//
15//===----------------------------------------------------------------------===//
16
Kristof Umanna37bba42018-08-13 18:22:22 +000017#include "UninitializedObject.h"
Kristof Umann56963ae2018-08-13 18:17:05 +000018#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19#include "clang/StaticAnalyzer/Core/Checker.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Csaba Dabise4bf4562019-08-22 00:36:42 +000021#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
Kristof Umann56963ae2018-08-13 18:17:05 +000022
23using namespace clang;
24using namespace clang::ento;
25
Kristof Umann015b0592018-08-13 18:43:08 +000026namespace {
27
28/// Represents a pointer or a reference field.
Richard Smith651d6832018-08-13 22:07:11 +000029class LocField final : public FieldNode {
Kristof Umann015b0592018-08-13 18:43:08 +000030 /// We'll store whether the pointee or the pointer itself is uninitialited.
31 const bool IsDereferenced;
32
33public:
34 LocField(const FieldRegion *FR, const bool IsDereferenced = true)
35 : FieldNode(FR), IsDereferenced(IsDereferenced) {}
36
37 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
38 if (IsDereferenced)
39 Out << "uninitialized pointee ";
40 else
41 Out << "uninitialized pointer ";
42 }
43
44 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
45
46 virtual void printNode(llvm::raw_ostream &Out) const override {
47 Out << getVariableName(getDecl());
48 }
49
50 virtual void printSeparator(llvm::raw_ostream &Out) const override {
51 if (getDecl()->getType()->isPointerType())
52 Out << "->";
53 else
54 Out << '.';
55 }
56};
57
Kristof Umannf0513792018-09-14 10:18:26 +000058/// 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.
Ilya Biryukov88ad9cf2018-09-14 11:28:48 +000060class NeedsCastLocField final : public FieldNode {
Kristof Umann5a424412018-08-14 08:20:51 +000061 QualType CastBackType;
62
63public:
64 NeedsCastLocField(const FieldRegion *FR, const QualType &T)
65 : FieldNode(FR), CastBackType(T) {}
66
67 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
68 Out << "uninitialized pointee ";
69 }
70
71 virtual void printPrefix(llvm::raw_ostream &Out) const override {
Kristof Umannf0513792018-09-14 10:18:26 +000072 // 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() << ">(";
Kristof Umann5a424412018-08-14 08:20:51 +000079 }
80
81 virtual void printNode(llvm::raw_ostream &Out) const override {
82 Out << getVariableName(getDecl()) << ')';
83 }
84
85 virtual void printSeparator(llvm::raw_ostream &Out) const override {
86 Out << "->";
87 }
88};
89
Kristof Umann8e5328b2018-10-11 11:58:53 +000090/// Represents a Loc field that points to itself.
91class CyclicLocField final : public FieldNode {
92
93public:
94 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
95
96 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
97 Out << "object references itself ";
98 }
99
100 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
101
102 virtual void printNode(llvm::raw_ostream &Out) const override {
103 Out << getVariableName(getDecl());
104 }
105
106 virtual void printSeparator(llvm::raw_ostream &Out) const override {
107 llvm_unreachable("CyclicLocField objects must be the last node of the "
108 "fieldchain!");
109 }
110};
111
Kristof Umann015b0592018-08-13 18:43:08 +0000112} // end of anonymous namespace
113
Kristof Umann56963ae2018-08-13 18:17:05 +0000114// Utility function declarations.
115
Kristof Umann8e5328b2018-10-11 11:58:53 +0000116struct DereferenceInfo {
117 const TypedValueRegion *R;
118 const bool NeedsCastBack;
119 const bool IsCyclic;
120 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
121 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
122};
Kristof Umannf0dd1012018-09-14 08:58:21 +0000123
124/// Dereferences \p FR and returns with the pointee's region, and whether it
125/// needs to be casted back to it's location type. If for whatever reason
126/// dereferencing fails, returns with None.
127static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
128 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000129
Kristof Umann8e5328b2018-10-11 11:58:53 +0000130/// Returns whether \p T can be (transitively) dereferenced to a void pointer
131/// type (void*, void**, ...).
132static bool isVoidPointer(QualType T);
133
Kristof Umann56963ae2018-08-13 18:17:05 +0000134//===----------------------------------------------------------------------===//
135// Methods for FindUninitializedFields.
136//===----------------------------------------------------------------------===//
137
Kristof Umannceb5f652018-09-14 09:07:40 +0000138bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000139 const FieldRegion *FR, FieldChainInfo LocalChain) {
140
Kristof Umann56963ae2018-08-13 18:17:05 +0000141 SVal V = State->getSVal(FR);
142
Kristof Umannf0513792018-09-14 10:18:26 +0000143 assert((isDereferencableType(FR->getDecl()->getType()) ||
144 V.getAs<nonloc::LocAsInteger>()) &&
Raphael Isemannb23ccec2018-12-10 12:37:46 +0000145 "This method only checks dereferenceable objects!");
Kristof Umannf0513792018-09-14 10:18:26 +0000146
Kristof Umann56963ae2018-08-13 18:17:05 +0000147 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
148 IsAnyFieldInitialized = true;
149 return false;
150 }
151
152 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000153 return addFieldToUninits(
Kristof Umann4ff77692018-11-18 11:34:10 +0000154 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
Kristof Umann56963ae2018-08-13 18:17:05 +0000155 }
156
Kristof Umann6cec6c42018-09-14 09:39:26 +0000157 if (!Opts.CheckPointeeInitialization) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000158 IsAnyFieldInitialized = true;
159 return false;
160 }
161
Kristof Umann56963ae2018-08-13 18:17:05 +0000162 // At this point the pointer itself is initialized and points to a valid
163 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000164 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000165 if (!DerefInfo) {
166 IsAnyFieldInitialized = true;
167 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000168 }
169
Kristof Umann8e5328b2018-10-11 11:58:53 +0000170 if (DerefInfo->IsCyclic)
Kristof Umann4ff77692018-11-18 11:34:10 +0000171 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
Kristof Umann8e5328b2018-10-11 11:58:53 +0000172
173 const TypedValueRegion *R = DerefInfo->R;
174 const bool NeedsCastBack = DerefInfo->NeedsCastBack;
Kristof Umann64601962018-08-21 10:45:21 +0000175
Kristof Umannf0dd1012018-09-14 08:58:21 +0000176 QualType DynT = R->getLocationType();
177 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000178
Kristof Umannf0dd1012018-09-14 08:58:21 +0000179 if (PointeeT->isStructureOrClassType()) {
180 if (NeedsCastBack)
181 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
182 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
183 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000184
Kristof Umannf0dd1012018-09-14 08:58:21 +0000185 if (PointeeT->isUnionType()) {
186 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000187 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000188 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
189 R);
190 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000191 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000192 IsAnyFieldInitialized = true;
193 return false;
194 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000195 }
196
Kristof Umannf0dd1012018-09-14 08:58:21 +0000197 if (PointeeT->isArrayType()) {
198 IsAnyFieldInitialized = true;
199 return false;
200 }
201
202 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000203 "At this point FR must either have a primitive dynamic type, or it "
204 "must be a null, undefined, unknown or concrete pointer!");
205
Kristof Umannf0dd1012018-09-14 08:58:21 +0000206 SVal PointeeV = State->getSVal(R);
207
208 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000209 if (NeedsCastBack)
Kristof Umann4ff77692018-11-18 11:34:10 +0000210 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
211 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
Kristof Umann5a424412018-08-14 08:20:51 +0000212 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000213
214 IsAnyFieldInitialized = true;
215 return false;
216}
217
218//===----------------------------------------------------------------------===//
219// Utility functions.
220//===----------------------------------------------------------------------===//
221
Kristof Umannf0dd1012018-09-14 08:58:21 +0000222static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
223 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000224
Kristof Umannf0dd1012018-09-14 08:58:21 +0000225 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000226
Kristof Umann64601962018-08-21 10:45:21 +0000227 SVal V = State->getSVal(FR);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000228 assert(V.getAsRegion() && "V must have an underlying region!");
Kristof Umann64601962018-08-21 10:45:21 +0000229
Kristof Umannf0513792018-09-14 10:18:26 +0000230 // If the static type of the field is a void pointer, or it is a
231 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
232 // dereferencing.
233 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
234 V.getAs<nonloc::LocAsInteger>();
235
Kristof Umannf0dd1012018-09-14 08:58:21 +0000236 // The region we'd like to acquire.
237 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
238 if (!R)
239 return None;
240
241 VisitedRegions.insert(R);
242
243 // We acquire the dynamic type of R,
244 QualType DynT = R->getLocationType();
245
246 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
247
248 R = Tmp->getAs<TypedValueRegion>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000249 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000250 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000251
Kristof Umannf0dd1012018-09-14 08:58:21 +0000252 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000253 if (!VisitedRegions.insert(R).second)
Kristof Umann8e5328b2018-10-11 11:58:53 +0000254 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
Kristof Umann64601962018-08-21 10:45:21 +0000255
Kristof Umannf0dd1012018-09-14 08:58:21 +0000256 DynT = R->getLocationType();
257 // In order to ensure that this loop terminates, we're also checking the
258 // dynamic type of R, since type hierarchy is finite.
259 if (isDereferencableType(DynT->getPointeeType()))
260 break;
Kristof Umann64601962018-08-21 10:45:21 +0000261 }
262
Artem Dergachev630f7da2019-08-28 18:44:38 +0000263 while (isa<CXXBaseObjectRegion>(R)) {
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000264 NeedsCastBack = true;
Artem Dergachev630f7da2019-08-28 18:44:38 +0000265 const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
266 if (!SuperR)
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000267 break;
Artem Dergachev630f7da2019-08-28 18:44:38 +0000268
269 R = SuperR;
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000270 }
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}