blob: f60fc0dfe0fc9d1c0b72018e617a2d1a5d45694a [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.
62class NeedsCastLocField : 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 Umann015b0592018-08-13 18:43:08 +000092} // end of anonymous namespace
93
Kristof Umann56963ae2018-08-13 18:17:05 +000094// Utility function declarations.
95
Kristof Umannceb5f652018-09-14 09:07:40 +000096/// Returns whether \p T can be (transitively) dereferenced to a void pointer
97/// type (void*, void**, ...).
Kristof Umann56963ae2018-08-13 18:17:05 +000098static bool isVoidPointer(QualType T);
99
Kristof Umannf0dd1012018-09-14 08:58:21 +0000100using DereferenceInfo = std::pair<const TypedValueRegion *, bool>;
101
102/// Dereferences \p FR and returns with the pointee's region, and whether it
103/// needs to be casted back to it's location type. If for whatever reason
104/// dereferencing fails, returns with None.
105static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
106 const FieldRegion *FR);
Kristof Umann64601962018-08-21 10:45:21 +0000107
Kristof Umann56963ae2018-08-13 18:17:05 +0000108//===----------------------------------------------------------------------===//
109// Methods for FindUninitializedFields.
110//===----------------------------------------------------------------------===//
111
Kristof Umannceb5f652018-09-14 09:07:40 +0000112bool FindUninitializedFields::isDereferencableUninit(
Kristof Umann56963ae2018-08-13 18:17:05 +0000113 const FieldRegion *FR, FieldChainInfo LocalChain) {
114
Kristof Umann56963ae2018-08-13 18:17:05 +0000115 SVal V = State->getSVal(FR);
116
Kristof Umannf0513792018-09-14 10:18:26 +0000117 assert((isDereferencableType(FR->getDecl()->getType()) ||
118 V.getAs<nonloc::LocAsInteger>()) &&
119 "This method only checks dereferencable objects!");
120
Kristof Umann56963ae2018-08-13 18:17:05 +0000121 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
122 IsAnyFieldInitialized = true;
123 return false;
124 }
125
126 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000127 return addFieldToUninits(
128 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000129 }
130
Kristof Umann6cec6c42018-09-14 09:39:26 +0000131 if (!Opts.CheckPointeeInitialization) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000132 IsAnyFieldInitialized = true;
133 return false;
134 }
135
Kristof Umann56963ae2018-08-13 18:17:05 +0000136 // At this point the pointer itself is initialized and points to a valid
137 // location, we'll now check the pointee.
Kristof Umannf0dd1012018-09-14 08:58:21 +0000138 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
Kristof Umann64601962018-08-21 10:45:21 +0000139 if (!DerefInfo) {
140 IsAnyFieldInitialized = true;
141 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000142 }
143
Kristof Umannf0dd1012018-09-14 08:58:21 +0000144 const TypedValueRegion *R = DerefInfo->first;
145 const bool NeedsCastBack = DerefInfo->second;
Kristof Umann64601962018-08-21 10:45:21 +0000146
Kristof Umannf0dd1012018-09-14 08:58:21 +0000147 QualType DynT = R->getLocationType();
148 QualType PointeeT = DynT->getPointeeType();
Kristof Umann56963ae2018-08-13 18:17:05 +0000149
Kristof Umannf0dd1012018-09-14 08:58:21 +0000150 if (PointeeT->isStructureOrClassType()) {
151 if (NeedsCastBack)
152 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
153 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
154 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000155
Kristof Umannf0dd1012018-09-14 08:58:21 +0000156 if (PointeeT->isUnionType()) {
157 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000158 if (NeedsCastBack)
Kristof Umannf0dd1012018-09-14 08:58:21 +0000159 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
160 return addFieldToUninits(LocalChain.add(LocField(FR)));
161 } else {
Kristof Umann56963ae2018-08-13 18:17:05 +0000162 IsAnyFieldInitialized = true;
163 return false;
164 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000165 }
166
Kristof Umannf0dd1012018-09-14 08:58:21 +0000167 if (PointeeT->isArrayType()) {
168 IsAnyFieldInitialized = true;
169 return false;
170 }
171
172 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000173 "At this point FR must either have a primitive dynamic type, or it "
174 "must be a null, undefined, unknown or concrete pointer!");
175
Kristof Umannf0dd1012018-09-14 08:58:21 +0000176 SVal PointeeV = State->getSVal(R);
177
178 if (isPrimitiveUninit(PointeeV)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000179 if (NeedsCastBack)
180 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000181 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann5a424412018-08-14 08:20:51 +0000182 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000183
184 IsAnyFieldInitialized = true;
185 return false;
186}
187
188//===----------------------------------------------------------------------===//
189// Utility functions.
190//===----------------------------------------------------------------------===//
191
192static bool isVoidPointer(QualType T) {
193 while (!T.isNull()) {
194 if (T->isVoidPointerType())
195 return true;
196 T = T->getPointeeType();
197 }
198 return false;
199}
Kristof Umann64601962018-08-21 10:45:21 +0000200
Kristof Umannf0dd1012018-09-14 08:58:21 +0000201static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
202 const FieldRegion *FR) {
Kristof Umann64601962018-08-21 10:45:21 +0000203
Kristof Umannf0dd1012018-09-14 08:58:21 +0000204 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
Kristof Umann64601962018-08-21 10:45:21 +0000205
Kristof Umann64601962018-08-21 10:45:21 +0000206 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 Umannf0513792018-09-14 10:18:26 +0000209 // If the static type of the field is a void pointer, or it is a
210 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
211 // dereferencing.
212 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
213 V.getAs<nonloc::LocAsInteger>();
214
Kristof Umannf0dd1012018-09-14 08:58:21 +0000215 // The region we'd like to acquire.
216 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
217 if (!R)
218 return None;
219
220 VisitedRegions.insert(R);
221
222 // We acquire the dynamic type of R,
223 QualType DynT = R->getLocationType();
224
225 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
226
227 R = Tmp->getAs<TypedValueRegion>();
Kristof Umannf0dd1012018-09-14 08:58:21 +0000228 if (!R)
Kristof Umann64601962018-08-21 10:45:21 +0000229 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000230
Kristof Umannf0dd1012018-09-14 08:58:21 +0000231 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
Kristof Umannceb5f652018-09-14 09:07:40 +0000232 // TODO: Should we report these fields too?
Kristof Umannf0dd1012018-09-14 08:58:21 +0000233 if (!VisitedRegions.insert(R).second)
Kristof Umann64601962018-08-21 10:45:21 +0000234 return None;
Kristof Umann64601962018-08-21 10:45:21 +0000235
Kristof Umannf0dd1012018-09-14 08:58:21 +0000236 DynT = R->getLocationType();
237 // In order to ensure that this loop terminates, we're also checking the
238 // dynamic type of R, since type hierarchy is finite.
239 if (isDereferencableType(DynT->getPointeeType()))
240 break;
Kristof Umann64601962018-08-21 10:45:21 +0000241 }
242
Kristof Umann3ef3dd72018-09-14 09:13:36 +0000243 while (R->getAs<CXXBaseObjectRegion>()) {
244 NeedsCastBack = true;
245
246 if (!isa<TypedValueRegion>(R->getSuperRegion()))
247 break;
248 R = R->getSuperRegion()->getAs<TypedValueRegion>();
249 }
250
Kristof Umannf0dd1012018-09-14 08:58:21 +0000251 return std::make_pair(R, NeedsCastBack);
Kristof Umann64601962018-08-21 10:45:21 +0000252}