blob: 61e96ef9ae7dd19d89d836b7daf92c86cb05b32a [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
Kristof Umann56963ae2018-08-13 18:17:05 +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.
34class LocField : public FieldNode {
35 /// 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
63} // end of anonymous namespace
64
Kristof Umann56963ae2018-08-13 18:17:05 +000065// Utility function declarations.
66
67/// Returns whether T can be (transitively) dereferenced to a void pointer type
68/// (void*, void**, ...). The type of the region behind a void pointer isn't
69/// known, and thus FD can not be analyzed.
70static bool isVoidPointer(QualType T);
71
72//===----------------------------------------------------------------------===//
73// Methods for FindUninitializedFields.
74//===----------------------------------------------------------------------===//
75
76// Note that pointers/references don't contain fields themselves, so in this
77// function we won't add anything to LocalChain.
78bool FindUninitializedFields::isPointerOrReferenceUninit(
79 const FieldRegion *FR, FieldChainInfo LocalChain) {
80
81 assert((FR->getDecl()->getType()->isPointerType() ||
82 FR->getDecl()->getType()->isReferenceType() ||
83 FR->getDecl()->getType()->isBlockPointerType()) &&
84 "This method only checks pointer/reference objects!");
85
86 SVal V = State->getSVal(FR);
87
88 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
89 IsAnyFieldInitialized = true;
90 return false;
91 }
92
93 if (V.isUndef()) {
Kristof Umann015b0592018-08-13 18:43:08 +000094 return addFieldToUninits(
95 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
Kristof Umann56963ae2018-08-13 18:17:05 +000096 }
97
98 if (!CheckPointeeInitialization) {
99 IsAnyFieldInitialized = true;
100 return false;
101 }
102
103 assert(V.getAs<loc::MemRegionVal>() &&
104 "At this point V must be loc::MemRegionVal!");
105 auto L = V.castAs<loc::MemRegionVal>();
106
107 // We can't reason about symbolic regions, assume its initialized.
108 // Note that this also avoids a potential infinite recursion, because
109 // constructors for list-like classes are checked without being called, and
110 // the Static Analyzer will construct a symbolic region for Node *next; or
111 // similar code snippets.
112 if (L.getRegion()->getSymbolicBase()) {
113 IsAnyFieldInitialized = true;
114 return false;
115 }
116
117 DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
118 if (!DynTInfo.isValid()) {
119 IsAnyFieldInitialized = true;
120 return false;
121 }
122
123 QualType DynT = DynTInfo.getType();
124
125 if (isVoidPointer(DynT)) {
126 IsAnyFieldInitialized = true;
127 return false;
128 }
129
130 // At this point the pointer itself is initialized and points to a valid
131 // location, we'll now check the pointee.
132 SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT);
133
134 // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
135 // int** -> int*).
136 while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) {
137 if (Tmp->getRegion()->getSymbolicBase()) {
138 IsAnyFieldInitialized = true;
139 return false;
140 }
141
142 DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
143 if (!DynTInfo.isValid()) {
144 IsAnyFieldInitialized = true;
145 return false;
146 }
147
148 DynT = DynTInfo.getType();
149 if (isVoidPointer(DynT)) {
150 IsAnyFieldInitialized = true;
151 return false;
152 }
153
154 DerefdV = State->getSVal(*Tmp, DynT);
155 }
156
157 // If FR is a pointer pointing to a non-primitive type.
158 if (Optional<nonloc::LazyCompoundVal> RecordV =
159 DerefdV.getAs<nonloc::LazyCompoundVal>()) {
160
161 const TypedValueRegion *R = RecordV->getRegion();
162
163 if (DynT->getPointeeType()->isStructureOrClassType())
Kristof Umann015b0592018-08-13 18:43:08 +0000164 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000165
166 if (DynT->getPointeeType()->isUnionType()) {
167 if (isUnionUninit(R)) {
Kristof Umann015b0592018-08-13 18:43:08 +0000168 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000169 } else {
170 IsAnyFieldInitialized = true;
171 return false;
172 }
173 }
174
175 if (DynT->getPointeeType()->isArrayType()) {
176 IsAnyFieldInitialized = true;
177 return false;
178 }
179
180 llvm_unreachable("All cases are handled!");
181 }
182
183 assert((isPrimitiveType(DynT->getPointeeType()) || DynT->isPointerType() ||
184 DynT->isReferenceType()) &&
185 "At this point FR must either have a primitive dynamic type, or it "
186 "must be a null, undefined, unknown or concrete pointer!");
187
188 if (isPrimitiveUninit(DerefdV))
Kristof Umann015b0592018-08-13 18:43:08 +0000189 return addFieldToUninits(LocalChain.add(LocField(FR)));
Kristof Umann56963ae2018-08-13 18:17:05 +0000190
191 IsAnyFieldInitialized = true;
192 return false;
193}
194
195//===----------------------------------------------------------------------===//
196// Utility functions.
197//===----------------------------------------------------------------------===//
198
199static bool isVoidPointer(QualType T) {
200 while (!T.isNull()) {
201 if (T->isVoidPointerType())
202 return true;
203 T = T->getPointeeType();
204 }
205 return false;
206}