• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /freebsd-13-stable/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/
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"
18#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19#include "clang/StaticAnalyzer/Core/Checker.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
22
23using namespace clang;
24using namespace clang::ento;
25
26namespace {
27
28/// Represents a pointer or a reference field.
29class LocField final : public FieldNode {
30  /// We'll store whether the pointee or the pointer itself is uninitialited.
31  const bool IsDereferenced;
32
33public:
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.
60class NeedsCastLocField final : public FieldNode {
61  QualType CastBackType;
62
63public:
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.
91class CyclicLocField final : public FieldNode {
92
93public:
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
116struct DereferenceInfo {
117  const TypedValueRegion *R;
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.
127static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
128                                                   const FieldRegion *FR);
129
130/// Returns whether \p T can be (transitively) dereferenced to a void pointer
131/// type (void*, void**, ...).
132static bool isVoidPointer(QualType T);
133
134//===----------------------------------------------------------------------===//
135//                   Methods for FindUninitializedFields.
136//===----------------------------------------------------------------------===//
137
138bool 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
222static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
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()) ||
234                       V.getAs<nonloc::LocAsInteger>();
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.
259    if (isDereferencableType(DynT->getPointeeType()))
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
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