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