blob: 72e256b717f5eb126c19069a8499349cc8507edd [file] [log] [blame]
Kristof Umann56963ae2018-08-13 18:17:05 +00001//===----- UninitializedPointer.cpp ------------------------------*- C++ -*-==//
2//
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
93/// Returns whether T can be (transitively) dereferenced to a void pointer type
94/// (void*, void**, ...). The type of the region behind a void pointer isn't
95/// known, and thus FD can not be analyzed.
96static bool isVoidPointer(QualType T);
97
Kristof Umann64601962018-08-21 10:45:21 +000098/// Dereferences \p V and returns the value and dynamic type of the pointee, as
Nico Weber5946e5b2018-08-27 14:23:50 +000099/// well as whether \p FR needs to be casted back to that type. If for whatever
Kristof Umann64601962018-08-21 10:45:21 +0000100/// reason dereferencing fails, returns with None.
101static llvm::Optional<std::tuple<SVal, QualType, bool>>
102dereference(ProgramStateRef State, const FieldRegion *FR);
103
Kristof Umann56963ae2018-08-13 18:17:05 +0000104//===----------------------------------------------------------------------===//
105// Methods for FindUninitializedFields.
106//===----------------------------------------------------------------------===//
107
108// Note that pointers/references don't contain fields themselves, so in this
109// function we won't add anything to LocalChain.
110bool FindUninitializedFields::isPointerOrReferenceUninit(
111 const FieldRegion *FR, FieldChainInfo LocalChain) {
112
George Karpenkove3b1d962018-08-13 23:32:15 +0000113 assert((FR->getDecl()->getType()->isAnyPointerType() ||
Kristof Umann56963ae2018-08-13 18:17:05 +0000114 FR->getDecl()->getType()->isReferenceType() ||
115 FR->getDecl()->getType()->isBlockPointerType()) &&
116 "This method only checks pointer/reference objects!");
117
118 SVal V = State->getSVal(FR);
119
120 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
121 IsAnyFieldInitialized = true;
122 return false;
123 }
124
125 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +0000126 return addFieldToUninits(
127 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000128 }
129
130 if (!CheckPointeeInitialization) {
131 IsAnyFieldInitialized = true;
132 return false;
133 }
134
Kristof Umann56963ae2018-08-13 18:17:05 +0000135 // At this point the pointer itself is initialized and points to a valid
136 // location, we'll now check the pointee.
Kristof Umann64601962018-08-21 10:45:21 +0000137 llvm::Optional<std::tuple<SVal, QualType, bool>> DerefInfo =
138 dereference(State, FR);
139 if (!DerefInfo) {
140 IsAnyFieldInitialized = true;
141 return false;
Kristof Umann56963ae2018-08-13 18:17:05 +0000142 }
143
Kristof Umann64601962018-08-21 10:45:21 +0000144 V = std::get<0>(*DerefInfo);
145 QualType DynT = std::get<1>(*DerefInfo);
146 bool NeedsCastBack = std::get<2>(*DerefInfo);
147
Kristof Umann56963ae2018-08-13 18:17:05 +0000148 // If FR is a pointer pointing to a non-primitive type.
149 if (Optional<nonloc::LazyCompoundVal> RecordV =
Kristof Umann64601962018-08-21 10:45:21 +0000150 V.getAs<nonloc::LazyCompoundVal>()) {
Kristof Umann56963ae2018-08-13 18:17:05 +0000151
152 const TypedValueRegion *R = RecordV->getRegion();
153
Kristof Umann5a424412018-08-14 08:20:51 +0000154 if (DynT->getPointeeType()->isStructureOrClassType()) {
155 if (NeedsCastBack)
156 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000157 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
Kristof Umann5a424412018-08-14 08:20:51 +0000158 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000159
160 if (DynT->getPointeeType()->isUnionType()) {
161 if (isUnionUninit(R)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000162 if (NeedsCastBack)
163 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000164 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000165 } else {
166 IsAnyFieldInitialized = true;
167 return false;
168 }
169 }
170
171 if (DynT->getPointeeType()->isArrayType()) {
172 IsAnyFieldInitialized = true;
173 return false;
174 }
175
176 llvm_unreachable("All cases are handled!");
177 }
178
Andrei Elovikov7d408ff2018-08-20 13:45:38 +0000179 assert((isPrimitiveType(DynT->getPointeeType()) || DynT->isAnyPointerType() ||
180 DynT->isReferenceType()) &&
Kristof Umann56963ae2018-08-13 18:17:05 +0000181 "At this point FR must either have a primitive dynamic type, or it "
182 "must be a null, undefined, unknown or concrete pointer!");
183
Kristof Umann64601962018-08-21 10:45:21 +0000184 if (isPrimitiveUninit(V)) {
Kristof Umann5a424412018-08-14 08:20:51 +0000185 if (NeedsCastBack)
186 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
Kristof Umann015b0592018-08-13 18:43:08 +0000187 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann5a424412018-08-14 08:20:51 +0000188 }
Kristof Umann56963ae2018-08-13 18:17:05 +0000189
190 IsAnyFieldInitialized = true;
191 return false;
192}
193
194//===----------------------------------------------------------------------===//
195// Utility functions.
196//===----------------------------------------------------------------------===//
197
198static bool isVoidPointer(QualType T) {
199 while (!T.isNull()) {
200 if (T->isVoidPointerType())
201 return true;
202 T = T->getPointeeType();
203 }
204 return false;
205}
Kristof Umann64601962018-08-21 10:45:21 +0000206
207static llvm::Optional<std::tuple<SVal, QualType, bool>>
208dereference(ProgramStateRef State, const FieldRegion *FR) {
209
210 DynamicTypeInfo DynTInfo;
211 QualType DynT;
212
213 // If the static type of the field is a void pointer, we need to cast it back
214 // to the dynamic type before dereferencing.
215 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
216
217 SVal V = State->getSVal(FR);
218 assert(V.getAs<loc::MemRegionVal>() && "V must be loc::MemRegionVal!");
219
220 // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
221 // int*).
222 // TODO: Dereference according to the dynamic type to avoid infinite loop for
223 // these kind of fields:
224 // int **ptr = reinterpret_cast<int **>(&ptr);
225 while (auto Tmp = V.getAs<loc::MemRegionVal>()) {
226 // We can't reason about symbolic regions, assume its initialized.
227 // Note that this also avoids a potential infinite recursion, because
228 // constructors for list-like classes are checked without being called, and
229 // the Static Analyzer will construct a symbolic region for Node *next; or
230 // similar code snippets.
231 if (Tmp->getRegion()->getSymbolicBase()) {
232 return None;
233 }
234
235 DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
236 if (!DynTInfo.isValid()) {
237 return None;
238 }
239
240 DynT = DynTInfo.getType();
241
242 if (isVoidPointer(DynT)) {
243 return None;
244 }
245
246 V = State->getSVal(*Tmp, DynT);
247 }
248
249 return std::make_tuple(V, DynT, NeedsCastBack);
250}