UninitializedPointee.cpp revision 344779
1//===----- UninitializedPointee.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 documentation about how the checker
14// works, refer to UninitializedObjectChecker.h.
15//
16//===----------------------------------------------------------------------===//
17
18#include "UninitializedObject.h"
19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20#include "clang/StaticAnalyzer/Core/Checker.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
23
24using namespace clang;
25using namespace clang::ento;
26
27namespace {
28
29/// Represents a pointer or a reference field.
30class LocField final : public FieldNode {
31  /// We'll store whether the pointee or the pointer itself is uninitialited.
32  const bool IsDereferenced;
33
34public:
35  LocField(const FieldRegion *FR, const bool IsDereferenced = true)
36      : FieldNode(FR), IsDereferenced(IsDereferenced) {}
37
38  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
39    if (IsDereferenced)
40      Out << "uninitialized pointee ";
41    else
42      Out << "uninitialized pointer ";
43  }
44
45  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
46
47  virtual void printNode(llvm::raw_ostream &Out) const override {
48    Out << getVariableName(getDecl());
49  }
50
51  virtual void printSeparator(llvm::raw_ostream &Out) const override {
52    if (getDecl()->getType()->isPointerType())
53      Out << "->";
54    else
55      Out << '.';
56  }
57};
58
59/// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
60/// needs to be casted back to its dynamic type for a correct note message.
61class NeedsCastLocField final : public FieldNode {
62  QualType CastBackType;
63
64public:
65  NeedsCastLocField(const FieldRegion *FR, const QualType &T)
66      : FieldNode(FR), CastBackType(T) {}
67
68  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
69    Out << "uninitialized pointee ";
70  }
71
72  virtual void printPrefix(llvm::raw_ostream &Out) const override {
73    // If this object is a nonloc::LocAsInteger.
74    if (getDecl()->getType()->isIntegerType())
75      Out << "reinterpret_cast";
76    // If this pointer's dynamic type is different then it's static type.
77    else
78      Out << "static_cast";
79    Out << '<' << CastBackType.getAsString() << ">(";
80  }
81
82  virtual void printNode(llvm::raw_ostream &Out) const override {
83    Out << getVariableName(getDecl()) << ')';
84  }
85
86  virtual void printSeparator(llvm::raw_ostream &Out) const override {
87    Out << "->";
88  }
89};
90
91/// Represents a Loc field that points to itself.
92class CyclicLocField final : public FieldNode {
93
94public:
95  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
96
97  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
98    Out << "object references itself ";
99  }
100
101  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
102
103  virtual void printNode(llvm::raw_ostream &Out) const override {
104    Out << getVariableName(getDecl());
105  }
106
107  virtual void printSeparator(llvm::raw_ostream &Out) const override {
108    llvm_unreachable("CyclicLocField objects must be the last node of the "
109                     "fieldchain!");
110  }
111};
112
113} // end of anonymous namespace
114
115// Utility function declarations.
116
117struct DereferenceInfo {
118  const TypedValueRegion *R;
119  const bool NeedsCastBack;
120  const bool IsCyclic;
121  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
122      : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
123};
124
125/// Dereferences \p FR and returns with the pointee's region, and whether it
126/// needs to be casted back to it's location type. If for whatever reason
127/// dereferencing fails, returns with None.
128static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
129                                                   const FieldRegion *FR);
130
131/// Returns whether \p T can be (transitively) dereferenced to a void pointer
132/// type (void*, void**, ...).
133static bool isVoidPointer(QualType T);
134
135//===----------------------------------------------------------------------===//
136//                   Methods for FindUninitializedFields.
137//===----------------------------------------------------------------------===//
138
139bool FindUninitializedFields::isDereferencableUninit(
140    const FieldRegion *FR, FieldChainInfo LocalChain) {
141
142  SVal V = State->getSVal(FR);
143
144  assert((isDereferencableType(FR->getDecl()->getType()) ||
145          V.getAs<nonloc::LocAsInteger>()) &&
146         "This method only checks dereferenceable objects!");
147
148  if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
149    IsAnyFieldInitialized = true;
150    return false;
151  }
152
153  if (V.isUndef()) {
154    return addFieldToUninits(
155        LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
156  }
157
158  if (!Opts.CheckPointeeInitialization) {
159    IsAnyFieldInitialized = true;
160    return false;
161  }
162
163  // At this point the pointer itself is initialized and points to a valid
164  // location, we'll now check the pointee.
165  llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
166  if (!DerefInfo) {
167    IsAnyFieldInitialized = true;
168    return false;
169  }
170
171  if (DerefInfo->IsCyclic)
172    return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
173
174  const TypedValueRegion *R = DerefInfo->R;
175  const bool NeedsCastBack = DerefInfo->NeedsCastBack;
176
177  QualType DynT = R->getLocationType();
178  QualType PointeeT = DynT->getPointeeType();
179
180  if (PointeeT->isStructureOrClassType()) {
181    if (NeedsCastBack)
182      return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
183    return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
184  }
185
186  if (PointeeT->isUnionType()) {
187    if (isUnionUninit(R)) {
188      if (NeedsCastBack)
189        return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
190                                 R);
191      return addFieldToUninits(LocalChain.add(LocField(FR)), R);
192    } else {
193      IsAnyFieldInitialized = true;
194      return false;
195    }
196  }
197
198  if (PointeeT->isArrayType()) {
199    IsAnyFieldInitialized = true;
200    return false;
201  }
202
203  assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
204         "At this point FR must either have a primitive dynamic type, or it "
205         "must be a null, undefined, unknown or concrete pointer!");
206
207  SVal PointeeV = State->getSVal(R);
208
209  if (isPrimitiveUninit(PointeeV)) {
210    if (NeedsCastBack)
211      return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
212    return addFieldToUninits(LocalChain.add(LocField(FR)), R);
213  }
214
215  IsAnyFieldInitialized = true;
216  return false;
217}
218
219//===----------------------------------------------------------------------===//
220//                           Utility functions.
221//===----------------------------------------------------------------------===//
222
223static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
224                                                   const FieldRegion *FR) {
225
226  llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
227
228  SVal V = State->getSVal(FR);
229  assert(V.getAsRegion() && "V must have an underlying region!");
230
231  // If the static type of the field is a void pointer, or it is a
232  // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
233  // dereferencing.
234  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
235                       V.getAs<nonloc::LocAsInteger>();
236
237  // The region we'd like to acquire.
238  const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
239  if (!R)
240    return None;
241
242  VisitedRegions.insert(R);
243
244  // We acquire the dynamic type of R,
245  QualType DynT = R->getLocationType();
246
247  while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
248
249    R = Tmp->getAs<TypedValueRegion>();
250    if (!R)
251      return None;
252
253    // We found a cyclic pointer, like int *ptr = (int *)&ptr.
254    if (!VisitedRegions.insert(R).second)
255      return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
256
257    DynT = R->getLocationType();
258    // In order to ensure that this loop terminates, we're also checking the
259    // dynamic type of R, since type hierarchy is finite.
260    if (isDereferencableType(DynT->getPointeeType()))
261      break;
262  }
263
264  while (R->getAs<CXXBaseObjectRegion>()) {
265    NeedsCastBack = true;
266
267    if (!isa<TypedValueRegion>(R->getSuperRegion()))
268      break;
269    R = R->getSuperRegion()->getAs<TypedValueRegion>();
270  }
271
272  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
273}
274
275static bool isVoidPointer(QualType T) {
276  while (!T.isNull()) {
277    if (T->isVoidPointerType())
278      return true;
279    T = T->getPointeeType();
280  }
281  return false;
282}
283