blob: 13633af665edf73e5a94e7a9b63ee489e5d0b629 [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//
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
Richard Smith651d6832018-08-13 22:07:11 +000021#include "../ClangSACheckers.h"
Kristof Umanna37bba42018-08-13 18:22:22 +000022#include "UninitializedObject.h"
Kristof Umann56963ae2018-08-13 18:17:05 +000023#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
28using namespace clang;
29using namespace clang::ento;
30
Kristof Umann015b0592018-08-13 18:43:08 +000031namespace {
32
33/// Represents a pointer or a reference field.
Richard Smith651d6832018-08-13 22:07:11 +000034class LocField final : public FieldNode {
Kristof Umann015b0592018-08-13 18:43:08 +000035 /// We'll store whether the pointee or the pointer itself is uninitialited.
36 const bool IsDereferenced;
37
38public:
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
Kristof Umann5a424412018-08-14 08:20:51 +000063/// Represents a void* field that needs to be casted back to its dynamic type
64/// for a correct note message.
65class NeedsCastLocField final : public FieldNode {
66 QualType CastBackType;
67
68public:
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
Kristof Umann015b0592018-08-13 18:43:08 +000089} // end of anonymous namespace
90
Kristof Umann56963ae2018-08-13 18:17:05 +000091// Utility function declarations.
92
Kristof Umannceb5f652018-09-14 09:07:40 +000093/// Returns whether \p T can be (transitively) dereferenced to a void pointer
94/// type (void*, void**, ...).
Kristof Umann56963ae2018-08-13 18:17:05 +000095static bool isVoidPointer(QualType T);
96
Kristof Umannf0dd1012018-09-14 08:58:21 +000097using 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.
102static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
103 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000104
Kristof Umann56963ae2018-08-13 18:17:05 +0000105//===----------------------------------------------------------------------===//
106// Methods for FindUninitializedFields.
107//===----------------------------------------------------------------------===//
108
Kristof Umannceb5f652018-09-14 09:07:40 +0000109bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000110 const FieldRegion *FR, FieldChainInfo LocalChain) {
111
Kristof Umannf0dd1012018-09-14 08:58:21 +0000112 assert(isDereferencableType(FR->getDecl()->getType()) &&
113 "This method only checks dereferencable objects!");
Kristof Umann56963ae2018-08-13 18:17:05 +0000114
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()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000123 return addFieldToUninits(
124 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000125 }
126
127 if (!CheckPointeeInitialization) {
128 IsAnyFieldInitialized = true;
129 return false;
130 }
131
Kristof Umann56963ae2018-08-13 18:17:05 +0000132 // At this point the pointer itself is initialized and points to a valid
133 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000134 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000135 if (!DerefInfo) {
136 IsAnyFieldInitialized = true;
137 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000138 }
139
Kristof Umannf0dd1012018-09-14 08:58:21 +0000140 const TypedValueRegion *R = DerefInfo->first;
141 const bool NeedsCastBack = DerefInfo->second;
Kristof Umann64601962018-08-21 10:45:21 +0000142
Kristof Umannf0dd1012018-09-14 08:58:21 +0000143 QualType DynT = R->getLocationType();
144 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000145
Kristof Umannf0dd1012018-09-14 08:58:21 +0000146 if (PointeeT->isStructureOrClassType()) {
147 if (NeedsCastBack)
148 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
149 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
150 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000151
Kristof Umannf0dd1012018-09-14 08:58:21 +0000152 if (PointeeT->isUnionType()) {
153 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000154 if (NeedsCastBack)
Kristof Umannf0dd1012018-09-14 08:58:21 +0000155 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
156 return addFieldToUninits(LocalChain.add(LocField(FR)));
157 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000158 IsAnyFieldInitialized = true;
159 return false;
160 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000161 }
162
Kristof Umannf0dd1012018-09-14 08:58:21 +0000163 if (PointeeT->isArrayType()) {
164 IsAnyFieldInitialized = true;
165 return false;
166 }
167
168 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000169 "At this point FR must either have a primitive dynamic type, or it "
170 "must be a null, undefined, unknown or concrete pointer!");
171
Kristof Umannf0dd1012018-09-14 08:58:21 +0000172 SVal PointeeV = State->getSVal(R);
173
174 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000175 if (NeedsCastBack)
176 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000177 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann5a424412018-08-14 08:20:51 +0000178 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000179
180 IsAnyFieldInitialized = true;
181 return false;
182}
183
184//===----------------------------------------------------------------------===//
185// Utility functions.
186//===----------------------------------------------------------------------===//
187
188static bool isVoidPointer(QualType T) {
189 while (!T.isNull()) {
190 if (T->isVoidPointerType())
191 return true;
192 T = T->getPointeeType();
193 }
194 return false;
195}
Kristof Umann64601962018-08-21 10:45:21 +0000196
Kristof Umannf0dd1012018-09-14 08:58:21 +0000197static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
198 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000199
Kristof Umannf0dd1012018-09-14 08:58:21 +0000200 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000201
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);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000207 assert(V.getAsRegion() && "V must have an underlying region!");
Kristof Umann64601962018-08-21 10:45:21 +0000208
Kristof Umannf0dd1012018-09-14 08:58:21 +0000209 // 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>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000222 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000223 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000224
Kristof Umannf0dd1012018-09-14 08:58:21 +0000225 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannceb5f652018-09-14 09:07:40 +0000226 // TODO: Should we report these fields too?
Kristof Umannf0dd1012018-09-14 08:58:21 +0000227 if (!VisitedRegions.insert(R).second)
Kristof Umann64601962018-08-21 10:45:21 +0000228 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000229
Kristof Umannf0dd1012018-09-14 08:58:21 +0000230 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;
Kristof Umann64601962018-08-21 10:45:21 +0000235 }
236
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000237 while (R->getAs<CXXBaseObjectRegion>()) {
238 NeedsCastBack = true;
239
240 if (!isa<TypedValueRegion>(R->getSuperRegion()))
241 break;
242 R = R->getSuperRegion()->getAs<TypedValueRegion>();
243 }
244
Kristof Umannf0dd1012018-09-14 08:58:21 +0000245 return std::make_pair(R, NeedsCastBack);
Kristof Umann64601962018-08-21 10:45:21 +0000246}