clang  10.0.0svn
UninitializedPointee.cpp
Go to the documentation of this file.
1 //===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines functions and methods for handling pointers and references
10 // to reduce the size and complexity of UninitializedObjectChecker.cpp.
11 //
12 // To read about command line options and documentation about how the checker
13 // works, refer to UninitializedObjectChecker.h.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "UninitializedObject.h"
22 
23 using namespace clang;
24 using namespace clang::ento;
25 
26 namespace {
27 
28 /// Represents a pointer or a reference field.
29 class LocField final : public FieldNode {
30  /// We'll store whether the pointee or the pointer itself is uninitialited.
31  const bool IsDereferenced;
32 
33 public:
34  LocField(const FieldRegion *FR, const bool IsDereferenced = true)
35  : FieldNode(FR), IsDereferenced(IsDereferenced) {}
36 
37  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
38  if (IsDereferenced)
39  Out << "uninitialized pointee ";
40  else
41  Out << "uninitialized pointer ";
42  }
43 
44  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
45 
46  virtual void printNode(llvm::raw_ostream &Out) const override {
47  Out << getVariableName(getDecl());
48  }
49 
50  virtual void printSeparator(llvm::raw_ostream &Out) const override {
51  if (getDecl()->getType()->isPointerType())
52  Out << "->";
53  else
54  Out << '.';
55  }
56 };
57 
58 /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
59 /// needs to be casted back to its dynamic type for a correct note message.
60 class NeedsCastLocField final : public FieldNode {
61  QualType CastBackType;
62 
63 public:
64  NeedsCastLocField(const FieldRegion *FR, const QualType &T)
65  : FieldNode(FR), CastBackType(T) {}
66 
67  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
68  Out << "uninitialized pointee ";
69  }
70 
71  virtual void printPrefix(llvm::raw_ostream &Out) const override {
72  // If this object is a nonloc::LocAsInteger.
73  if (getDecl()->getType()->isIntegerType())
74  Out << "reinterpret_cast";
75  // If this pointer's dynamic type is different then it's static type.
76  else
77  Out << "static_cast";
78  Out << '<' << CastBackType.getAsString() << ">(";
79  }
80 
81  virtual void printNode(llvm::raw_ostream &Out) const override {
82  Out << getVariableName(getDecl()) << ')';
83  }
84 
85  virtual void printSeparator(llvm::raw_ostream &Out) const override {
86  Out << "->";
87  }
88 };
89 
90 /// Represents a Loc field that points to itself.
91 class CyclicLocField final : public FieldNode {
92 
93 public:
94  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
95 
96  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
97  Out << "object references itself ";
98  }
99 
100  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
101 
102  virtual void printNode(llvm::raw_ostream &Out) const override {
103  Out << getVariableName(getDecl());
104  }
105 
106  virtual void printSeparator(llvm::raw_ostream &Out) const override {
107  llvm_unreachable("CyclicLocField objects must be the last node of the "
108  "fieldchain!");
109  }
110 };
111 
112 } // end of anonymous namespace
113 
114 // Utility function declarations.
115 
118  const bool NeedsCastBack;
119  const bool IsCyclic;
120  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
121  : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
122 };
123 
124 /// Dereferences \p FR and returns with the pointee's region, and whether it
125 /// needs to be casted back to it's location type. If for whatever reason
126 /// dereferencing fails, returns with None.
128  const FieldRegion *FR);
129 
130 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
131 /// type (void*, void**, ...).
132 static bool isVoidPointer(QualType T);
133 
134 //===----------------------------------------------------------------------===//
135 // Methods for FindUninitializedFields.
136 //===----------------------------------------------------------------------===//
137 
138 bool FindUninitializedFields::isDereferencableUninit(
139  const FieldRegion *FR, FieldChainInfo LocalChain) {
140 
141  SVal V = State->getSVal(FR);
142 
143  assert((isDereferencableType(FR->getDecl()->getType()) ||
144  V.getAs<nonloc::LocAsInteger>()) &&
145  "This method only checks dereferenceable objects!");
146 
147  if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
148  IsAnyFieldInitialized = true;
149  return false;
150  }
151 
152  if (V.isUndef()) {
153  return addFieldToUninits(
154  LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
155  }
156 
157  if (!Opts.CheckPointeeInitialization) {
158  IsAnyFieldInitialized = true;
159  return false;
160  }
161 
162  // At this point the pointer itself is initialized and points to a valid
163  // location, we'll now check the pointee.
164  llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
165  if (!DerefInfo) {
166  IsAnyFieldInitialized = true;
167  return false;
168  }
169 
170  if (DerefInfo->IsCyclic)
171  return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
172 
173  const TypedValueRegion *R = DerefInfo->R;
174  const bool NeedsCastBack = DerefInfo->NeedsCastBack;
175 
176  QualType DynT = R->getLocationType();
177  QualType PointeeT = DynT->getPointeeType();
178 
179  if (PointeeT->isStructureOrClassType()) {
180  if (NeedsCastBack)
181  return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
182  return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
183  }
184 
185  if (PointeeT->isUnionType()) {
186  if (isUnionUninit(R)) {
187  if (NeedsCastBack)
188  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
189  R);
190  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
191  } else {
192  IsAnyFieldInitialized = true;
193  return false;
194  }
195  }
196 
197  if (PointeeT->isArrayType()) {
198  IsAnyFieldInitialized = true;
199  return false;
200  }
201 
202  assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
203  "At this point FR must either have a primitive dynamic type, or it "
204  "must be a null, undefined, unknown or concrete pointer!");
205 
206  SVal PointeeV = State->getSVal(R);
207 
208  if (isPrimitiveUninit(PointeeV)) {
209  if (NeedsCastBack)
210  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
211  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
212  }
213 
214  IsAnyFieldInitialized = true;
215  return false;
216 }
217 
218 //===----------------------------------------------------------------------===//
219 // Utility functions.
220 //===----------------------------------------------------------------------===//
221 
223  const FieldRegion *FR) {
224 
225  llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
226 
227  SVal V = State->getSVal(FR);
228  assert(V.getAsRegion() && "V must have an underlying region!");
229 
230  // If the static type of the field is a void pointer, or it is a
231  // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
232  // dereferencing.
233  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
235 
236  // The region we'd like to acquire.
237  const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
238  if (!R)
239  return None;
240 
241  VisitedRegions.insert(R);
242 
243  // We acquire the dynamic type of R,
244  QualType DynT = R->getLocationType();
245 
246  while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
247 
248  R = Tmp->getAs<TypedValueRegion>();
249  if (!R)
250  return None;
251 
252  // We found a cyclic pointer, like int *ptr = (int *)&ptr.
253  if (!VisitedRegions.insert(R).second)
254  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
255 
256  DynT = R->getLocationType();
257  // In order to ensure that this loop terminates, we're also checking the
258  // dynamic type of R, since type hierarchy is finite.
260  break;
261  }
262 
263  while (isa<CXXBaseObjectRegion>(R)) {
264  NeedsCastBack = true;
265  const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
266  if (!SuperR)
267  break;
268 
269  R = SuperR;
270  }
271 
272  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
273 }
274 
275 static bool isVoidPointer(QualType T) {
276  while (!T.isNull()) {
277  if (T->isVoidPointerType())
278  return true;
279  T = T->getPointeeType();
280  }
281  return false;
282 }
TypedValueRegion - An abstract class representing regions having a typed value.
Definition: MemRegion.h:530
A (possibly-)qualified type.
Definition: Type.h:643
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
bool isArrayType() const
Definition: Type.h:6447
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
bool isPrimitiveType(const QualType &T)
Returns true if T is a primitive type.
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6858
LineState State
FieldChainInfo add(const FieldNodeT &FN)
Constructs a new FieldChainInfo object with FN appended.
const FieldDecl * getDecl() const
Definition: MemRegion.h:1017
static llvm::Optional< DereferenceInfo > dereference(ProgramStateRef State, const FieldRegion *FR)
Dereferences FR and returns with the pointee&#39;s region, and whether it needs to be casted back to it&#39;s...
bool isUnknown() const
Definition: SVals.h:136
bool isDereferencableType(const QualType &T)
const RegionTy * getAs() const
Definition: MemRegion.h:1228
std::string getVariableName(const FieldDecl *Field)
Returns with Field&#39;s name.
#define V(N, I)
Definition: ASTContext.h:2921
const TypedValueRegion * R
bool isUnionType() const
Definition: Type.cpp:527
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:708
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:111
bool isVoidPointerType() const
Definition: Type.cpp:521
static bool isVoidPointer(QualType T)
Returns whether T can be (transitively) dereferenced to a void pointer type (void*, void**, ...).
bool isStructureOrClassType() const
Definition: Type.cpp:513
const MemRegion * getAsRegion() const
Definition: SVals.cpp:151
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:75
Represents a field chain.
Dataflow Directional Tag Classes.
A lightweight polymorphic wrapper around FieldRegion *.
bool isUndef() const
Definition: SVals.h:140
QualType getType() const
Definition: Decl.h:655