blob: fa7cf1888bd45423c165f339a3feff4e0de7ea2a [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 Umann5a424412018-08-14 08:20:51 +000060/// Represents a void* field that needs to be casted back to its dynamic type
61/// for a correct note message.
62class NeedsCastLocField final : public FieldNode {
63 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 {
74 Out << "static_cast" << '<' << CastBackType.getAsString() << ">(";
75 }
76
77 virtual void printNode(llvm::raw_ostream &Out) const override {
78 Out << getVariableName(getDecl()) << ')';
79 }
80
81 virtual void printSeparator(llvm::raw_ostream &Out) const override {
82 Out << "->";
83 }
84};
85
Kristof Umann015b0592018-08-13 18:43:08 +000086} // end of anonymous namespace
87
Kristof Umann56963ae2018-08-13 18:17:05 +000088// Utility function declarations.
89
Kristof Umannceb5f652018-09-14 09:07:40 +000090/// Returns whether \p T can be (transitively) dereferenced to a void pointer
91/// type (void*, void**, ...).
Kristof Umann56963ae2018-08-13 18:17:05 +000092static bool isVoidPointer(QualType T);
93
Kristof Umannf0dd1012018-09-14 08:58:21 +000094using DereferenceInfo = std::pair<const TypedValueRegion *, bool>;
95
96/// Dereferences \p FR and returns with the pointee's region, and whether it
97/// needs to be casted back to it's location type. If for whatever reason
98/// dereferencing fails, returns with None.
99static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
100 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000101
Kristof Umann56963ae2018-08-13 18:17:05 +0000102//===----------------------------------------------------------------------===//
103// Methods for FindUninitializedFields.
104//===----------------------------------------------------------------------===//
105
Kristof Umannceb5f652018-09-14 09:07:40 +0000106bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000107 const FieldRegion *FR, FieldChainInfo LocalChain) {
108
Kristof Umannf0dd1012018-09-14 08:58:21 +0000109 assert(isDereferencableType(FR->getDecl()->getType()) &&
110 "This method only checks dereferencable objects!");
Kristof Umann56963ae2018-08-13 18:17:05 +0000111
112 SVal V = State->getSVal(FR);
113
114 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
115 IsAnyFieldInitialized = true;
116 return false;
117 }
118
119 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000120 return addFieldToUninits(
121 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000122 }
123
Kristof Umann6cec6c42018-09-14 09:39:26 +0000124 if (!Opts.CheckPointeeInitialization) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000125 IsAnyFieldInitialized = true;
126 return false;
127 }
128
Kristof Umann56963ae2018-08-13 18:17:05 +0000129 // At this point the pointer itself is initialized and points to a valid
130 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000131 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000132 if (!DerefInfo) {
133 IsAnyFieldInitialized = true;
134 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000135 }
136
Kristof Umannf0dd1012018-09-14 08:58:21 +0000137 const TypedValueRegion *R = DerefInfo->first;
138 const bool NeedsCastBack = DerefInfo->second;
Kristof Umann64601962018-08-21 10:45:21 +0000139
Kristof Umannf0dd1012018-09-14 08:58:21 +0000140 QualType DynT = R->getLocationType();
141 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000142
Kristof Umannf0dd1012018-09-14 08:58:21 +0000143 if (PointeeT->isStructureOrClassType()) {
144 if (NeedsCastBack)
145 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
146 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
147 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000148
Kristof Umannf0dd1012018-09-14 08:58:21 +0000149 if (PointeeT->isUnionType()) {
150 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000151 if (NeedsCastBack)
Kristof Umannf0dd1012018-09-14 08:58:21 +0000152 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
153 return addFieldToUninits(LocalChain.add(LocField(FR)));
154 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000155 IsAnyFieldInitialized = true;
156 return false;
157 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000158 }
159
Kristof Umannf0dd1012018-09-14 08:58:21 +0000160 if (PointeeT->isArrayType()) {
161 IsAnyFieldInitialized = true;
162 return false;
163 }
164
165 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000166 "At this point FR must either have a primitive dynamic type, or it "
167 "must be a null, undefined, unknown or concrete pointer!");
168
Kristof Umannf0dd1012018-09-14 08:58:21 +0000169 SVal PointeeV = State->getSVal(R);
170
171 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000172 if (NeedsCastBack)
173 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000174 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann5a424412018-08-14 08:20:51 +0000175 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000176
177 IsAnyFieldInitialized = true;
178 return false;
179}
180
181//===----------------------------------------------------------------------===//
182// Utility functions.
183//===----------------------------------------------------------------------===//
184
185static bool isVoidPointer(QualType T) {
186 while (!T.isNull()) {
187 if (T->isVoidPointerType())
188 return true;
189 T = T->getPointeeType();
190 }
191 return false;
192}
Kristof Umann64601962018-08-21 10:45:21 +0000193
Kristof Umannf0dd1012018-09-14 08:58:21 +0000194static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
195 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000196
Kristof Umannf0dd1012018-09-14 08:58:21 +0000197 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000198
199 // If the static type of the field is a void pointer, we need to cast it back
200 // to the dynamic type before dereferencing.
201 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
202
203 SVal V = State->getSVal(FR);
Kristof Umannf0dd1012018-09-14 08:58:21 +0000204 assert(V.getAsRegion() && "V must have an underlying region!");
Kristof Umann64601962018-08-21 10:45:21 +0000205
Kristof Umannf0dd1012018-09-14 08:58:21 +0000206 // The region we'd like to acquire.
207 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
208 if (!R)
209 return None;
210
211 VisitedRegions.insert(R);
212
213 // We acquire the dynamic type of R,
214 QualType DynT = R->getLocationType();
215
216 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
217
218 R = Tmp->getAs<TypedValueRegion>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000219 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000220 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000221
Kristof Umannf0dd1012018-09-14 08:58:21 +0000222 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannceb5f652018-09-14 09:07:40 +0000223 // TODO: Should we report these fields too?
Kristof Umannf0dd1012018-09-14 08:58:21 +0000224 if (!VisitedRegions.insert(R).second)
Kristof Umann64601962018-08-21 10:45:21 +0000225 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000226
Kristof Umannf0dd1012018-09-14 08:58:21 +0000227 DynT = R->getLocationType();
228 // In order to ensure that this loop terminates, we're also checking the
229 // dynamic type of R, since type hierarchy is finite.
230 if (isDereferencableType(DynT->getPointeeType()))
231 break;
Kristof Umann64601962018-08-21 10:45:21 +0000232 }
233
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000234 while (R->getAs<CXXBaseObjectRegion>()) {
235 NeedsCastBack = true;
236
237 if (!isa<TypedValueRegion>(R->getSuperRegion()))
238 break;
239 R = R->getSuperRegion()->getAs<TypedValueRegion>();
240 }
241
Kristof Umannf0dd1012018-09-14 08:58:21 +0000242 return std::make_pair(R, NeedsCastBack);
Kristof Umann64601962018-08-21 10:45:21 +0000243}