clang  16.0.0git
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  void printNoteMsg(llvm::raw_ostream &Out) const override {
38  if (IsDereferenced)
39  Out << "uninitialized pointee ";
40  else
41  Out << "uninitialized pointer ";
42  }
43 
44  void printPrefix(llvm::raw_ostream &Out) const override {}
45 
46  void printNode(llvm::raw_ostream &Out) const override {
47  Out << getVariableName(getDecl());
48  }
49 
50  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  void printNoteMsg(llvm::raw_ostream &Out) const override {
68  Out << "uninitialized pointee ";
69  }
70 
71  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  void printNode(llvm::raw_ostream &Out) const override {
82  Out << getVariableName(getDecl()) << ')';
83  }
84 
85  void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
86 };
87 
88 /// Represents a Loc field that points to itself.
89 class CyclicLocField final : public FieldNode {
90 
91 public:
92  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
93 
94  void printNoteMsg(llvm::raw_ostream &Out) const override {
95  Out << "object references itself ";
96  }
97 
98  void printPrefix(llvm::raw_ostream &Out) const override {}
99 
100  void printNode(llvm::raw_ostream &Out) const override {
101  Out << getVariableName(getDecl());
102  }
103 
104  void printSeparator(llvm::raw_ostream &Out) const override {
105  llvm_unreachable("CyclicLocField objects must be the last node of the "
106  "fieldchain!");
107  }
108 };
109 
110 } // end of anonymous namespace
111 
112 // Utility function declarations.
113 
116  const bool NeedsCastBack;
117  const bool IsCyclic;
118  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
119  : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
120 };
121 
122 /// Dereferences \p FR and returns with the pointee's region, and whether it
123 /// needs to be casted back to it's location type. If for whatever reason
124 /// dereferencing fails, returns with None.
126  const FieldRegion *FR);
127 
128 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
129 /// type (void*, void**, ...).
130 static bool isVoidPointer(QualType T);
131 
132 //===----------------------------------------------------------------------===//
133 // Methods for FindUninitializedFields.
134 //===----------------------------------------------------------------------===//
135 
136 bool FindUninitializedFields::isDereferencableUninit(
137  const FieldRegion *FR, FieldChainInfo LocalChain) {
138 
139  SVal V = State->getSVal(FR);
140 
141  assert((isDereferencableType(FR->getDecl()->getType()) ||
142  isa<nonloc::LocAsInteger>(V)) &&
143  "This method only checks dereferenceable objects!");
144 
145  if (V.isUnknown() || isa<loc::ConcreteInt>(V)) {
146  IsAnyFieldInitialized = true;
147  return false;
148  }
149 
150  if (V.isUndef()) {
151  return addFieldToUninits(
152  LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
153  }
154 
155  if (!Opts.CheckPointeeInitialization) {
156  IsAnyFieldInitialized = true;
157  return false;
158  }
159 
160  // At this point the pointer itself is initialized and points to a valid
161  // location, we'll now check the pointee.
162  llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
163  if (!DerefInfo) {
164  IsAnyFieldInitialized = true;
165  return false;
166  }
167 
168  if (DerefInfo->IsCyclic)
169  return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
170 
171  const TypedValueRegion *R = DerefInfo->R;
172  const bool NeedsCastBack = DerefInfo->NeedsCastBack;
173 
174  QualType DynT = R->getLocationType();
175  QualType PointeeT = DynT->getPointeeType();
176 
177  if (PointeeT->isStructureOrClassType()) {
178  if (NeedsCastBack)
179  return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
180  return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
181  }
182 
183  if (PointeeT->isUnionType()) {
184  if (isUnionUninit(R)) {
185  if (NeedsCastBack)
186  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
187  R);
188  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
189  } else {
190  IsAnyFieldInitialized = true;
191  return false;
192  }
193  }
194 
195  if (PointeeT->isArrayType()) {
196  IsAnyFieldInitialized = true;
197  return false;
198  }
199 
200  assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
201  "At this point FR must either have a primitive dynamic type, or it "
202  "must be a null, undefined, unknown or concrete pointer!");
203 
204  SVal PointeeV = State->getSVal(R);
205 
206  if (isPrimitiveUninit(PointeeV)) {
207  if (NeedsCastBack)
208  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
209  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
210  }
211 
212  IsAnyFieldInitialized = true;
213  return false;
214 }
215 
216 //===----------------------------------------------------------------------===//
217 // Utility functions.
218 //===----------------------------------------------------------------------===//
219 
221  const FieldRegion *FR) {
222 
223  llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
224 
225  SVal V = State->getSVal(FR);
226  assert(V.getAsRegion() && "V must have an underlying region!");
227 
228  // If the static type of the field is a void pointer, or it is a
229  // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
230  // dereferencing.
231  bool NeedsCastBack =
232  isVoidPointer(FR->getDecl()->getType()) || isa<nonloc::LocAsInteger>(V);
233 
234  // The region we'd like to acquire.
235  const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
236  if (!R)
237  return None;
238 
239  VisitedRegions.insert(R);
240 
241  // We acquire the dynamic type of R,
242  QualType DynT = R->getLocationType();
243 
244  while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
245 
246  R = Tmp->getAs<TypedValueRegion>();
247  if (!R)
248  return None;
249 
250  // We found a cyclic pointer, like int *ptr = (int *)&ptr.
251  if (!VisitedRegions.insert(R).second)
252  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
253 
254  DynT = R->getLocationType();
255  // In order to ensure that this loop terminates, we're also checking the
256  // dynamic type of R, since type hierarchy is finite.
258  break;
259  }
260 
261  while (isa<CXXBaseObjectRegion>(R)) {
262  NeedsCastBack = true;
263  const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
264  if (!SuperR)
265  break;
266 
267  R = SuperR;
268  }
269 
270  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
271 }
272 
273 static bool isVoidPointer(QualType T) {
274  while (!T.isNull()) {
275  if (T->isVoidPointerType())
276  return true;
277  T = T->getPointeeType();
278  }
279  return false;
280 }
DereferenceInfo::DereferenceInfo
DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
Definition: UninitializedPointee.cpp:118
isVoidPointer
static bool isVoidPointer(QualType T)
Returns whether T can be (transitively) dereferenced to a void pointer type (void*,...
Definition: UninitializedPointee.cpp:273
UninitializedObject.h
DereferenceInfo::IsCyclic
const bool IsCyclic
Definition: UninitializedPointee.cpp:117
clang::Type::isVoidPointerType
bool isVoidPointerType() const
Definition: Type.cpp:589
DereferenceInfo
Definition: UninitializedPointee.cpp:114
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:737
clang::ento::isPrimitiveType
bool isPrimitiveType(const QualType &T)
Returns true if T is a primitive type.
Definition: UninitializedObject.h:324
llvm::Optional
Definition: LLVM.h:40
clang::ento
Definition: CocoaConventions.h:23
clang::ento::MemRegion
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:95
clang::ento::getVariableName
std::string getVariableName(const FieldDecl *Field)
Returns with Field's name.
Definition: UninitializedObjectChecker.cpp:579
V
#define V(N, I)
Definition: ASTContext.h:3237
printNode
static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match, std::string *Result)
Definition: Stencil.cpp:46
clang::ento::UninitObjCheckerOptions::CheckPointeeInitialization
bool CheckPointeeInitialization
Definition: UninitializedObject.h:76
clang::ento::isDereferencableType
bool isDereferencableType(const QualType &T)
Definition: UninitializedObject.h:330
clang::Type::getPointeeType
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:625
clang::ento::FieldRegion::getDecl
const LLVM_ATTRIBUTE_RETURNS_NONNULL FieldDecl * getDecl() const override
Definition: MemRegion.h:1115
clang::ento::FieldRegion
Definition: MemRegion.h:1096
clang::ento::MemRegion::getAs
const RegionTy * getAs() const
Definition: MemRegion.h:1337
clang::Type::isUnionType
bool isUnionType() const
Definition: Type.cpp:595
DereferenceInfo::R
const TypedValueRegion * R
Definition: UninitializedPointee.cpp:115
dereference
static llvm::Optional< DereferenceInfo > dereference(ProgramStateRef State, const FieldRegion *FR)
Dereferences FR and returns with the pointee's region, and whether it needs to be casted back to it's...
Definition: UninitializedPointee.cpp:220
BugType.h
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:802
State
LineState State
Definition: UnwrappedLineFormatter.cpp:1147
CheckerContext.h
clang::Type::isStructureOrClassType
bool isStructureOrClassType() const
Definition: Type.cpp:581
Checker.h
clang::ento::FieldChainInfo::add
FieldChainInfo add(const FieldNodeT &FN)
Constructs a new FieldChainInfo object with FN appended.
Definition: UninitializedObject.h:337
clang::ento::FieldNode
A lightweight polymorphic wrapper around FieldRegion *.
Definition: UninitializedObject.h:85
clang
Definition: CalledOnceCheck.h:17
clang::Type::isArrayType
bool isArrayType() const
Definition: Type.h:6949
clang::ento::SubRegion::getSuperRegion
const LLVM_ATTRIBUTE_RETURNS_NONNULL MemRegion * getSuperRegion() const
Definition: MemRegion.h:455
DereferenceInfo::NeedsCastBack
const bool NeedsCastBack
Definition: UninitializedPointee.cpp:116
clang::ento::SVal
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:73
clang::ento::TypedValueRegion
TypedValueRegion - An abstract class representing regions having a typed value.
Definition: MemRegion.h:531
DynamicType.h
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:712
clang::ento::TypedValueRegion::getLocationType
QualType getLocationType() const override
Definition: MemRegion.h:542
clang::ento::FieldChainInfo
Represents a field chain.
Definition: UninitializedObject.h:160
llvm::IntrusiveRefCntPtr< const ProgramState >