Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
Line
Count
Source (jump to first uncovered line)
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
#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
76
      : FieldNode(FR), IsDereferenced(IsDereferenced) {}
37
38
28
  void printNoteMsg(llvm::raw_ostream &Out) const override {
39
28
    if (IsDereferenced)
40
18
      Out << "uninitialized pointee ";
41
10
    else
42
10
      Out << "uninitialized pointer ";
43
28
  }
44
45
62
  void printPrefix(llvm::raw_ostream &Out) const override {}
46
47
62
  void printNode(llvm::raw_ostream &Out) const override {
48
62
    Out << getVariableName(getDecl());
49
62
  }
50
51
34
  void printSeparator(llvm::raw_ostream &Out) const override {
52
34
    if (getDecl()->getType()->isPointerType())
53
14
      Out << "->";
54
20
    else
55
20
      Out << '.';
56
34
  }
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
15
      : FieldNode(FR), CastBackType(T) {}
67
68
6
  void printNoteMsg(llvm::raw_ostream &Out) const override {
69
6
    Out << "uninitialized pointee ";
70
6
  }
71
72
21
  void printPrefix(llvm::raw_ostream &Out) const override {
73
    // If this object is a nonloc::LocAsInteger.
74
21
    if (getDecl()->getType()->isIntegerType())
75
2
      Out << "reinterpret_cast";
76
    // If this pointer's dynamic type is different then it's static type.
77
19
    else
78
19
      Out << "static_cast";
79
21
    Out << '<' << CastBackType.getAsString() << ">(";
80
21
  }
81
82
21
  void printNode(llvm::raw_ostream &Out) const override {
83
21
    Out << getVariableName(getDecl()) << ')';
84
21
  }
85
86
15
  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
6
  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
94
95
6
  void printNoteMsg(llvm::raw_ostream &Out) const override {
96
6
    Out << "object references itself ";
97
6
  }
98
99
6
  void printPrefix(llvm::raw_ostream &Out) const override {}
100
101
6
  void printNode(llvm::raw_ostream &Out) const override {
102
6
    Out << getVariableName(getDecl());
103
6
  }
104
105
0
  void printSeparator(llvm::raw_ostream &Out) const override {
106
0
    llvm_unreachable("CyclicLocField objects must be the last node of the "
107
0
                     "fieldchain!");
108
0
  }
109
};
110
111
} // end of anonymous namespace
112
113
// Utility function declarations.
114
115
struct DereferenceInfo {
116
  const TypedValueRegion *R;
117
  const bool NeedsCastBack;
118
  const bool IsCyclic;
119
  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
120
113
      : 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
163
    const FieldRegion *FR, FieldChainInfo LocalChain) {
139
140
163
  SVal V = State->getSVal(FR);
141
142
163
  assert((isDereferencableType(FR->getDecl()->getType()) ||
143
163
          isa<nonloc::LocAsInteger>(V)) &&
144
163
         "This method only checks dereferenceable objects!");
145
146
163
  if (V.isUnknown() || 
isa<loc::ConcreteInt>(V)159
) {
147
17
    IsAnyFieldInitialized = true;
148
17
    return false;
149
17
  }
150
151
146
  if (V.isUndef()) {
152
10
    return addFieldToUninits(
153
10
        LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
154
10
  }
155
156
136
  if (!Opts.CheckPointeeInitialization) {
157
1
    IsAnyFieldInitialized = true;
158
1
    return false;
159
1
  }
160
161
  // At this point the pointer itself is initialized and points to a valid
162
  // location, we'll now check the pointee.
163
135
  std::optional<DereferenceInfo> DerefInfo = dereference(State, FR);
164
135
  if (!DerefInfo) {
165
22
    IsAnyFieldInitialized = true;
166
22
    return false;
167
22
  }
168
169
113
  if (DerefInfo->IsCyclic)
170
6
    return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
171
172
107
  const TypedValueRegion *R = DerefInfo->R;
173
107
  const bool NeedsCastBack = DerefInfo->NeedsCastBack;
174
175
107
  QualType DynT = R->getLocationType();
176
107
  QualType PointeeT = DynT->getPointeeType();
177
178
107
  if (PointeeT->isStructureOrClassType()) {
179
53
    if (NeedsCastBack)
180
9
      return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
181
44
    return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
182
53
  }
183
184
54
  if (PointeeT->isUnionType()) {
185
4
    if (isUnionUninit(R)) {
186
0
      if (NeedsCastBack)
187
0
        return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
188
0
                                 R);
189
0
      return addFieldToUninits(LocalChain.add(LocField(FR)), R);
190
4
    } else {
191
4
      IsAnyFieldInitialized = true;
192
4
      return false;
193
4
    }
194
4
  }
195
196
50
  if (PointeeT->isArrayType()) {
197
2
    IsAnyFieldInitialized = true;
198
2
    return false;
199
2
  }
200
201
48
  assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
202
48
         "At this point FR must either have a primitive dynamic type, or it "
203
48
         "must be a null, undefined, unknown or concrete pointer!");
204
205
48
  SVal PointeeV = State->getSVal(R);
206
207
48
  if (isPrimitiveUninit(PointeeV)) {
208
28
    if (NeedsCastBack)
209
6
      return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
210
22
    return addFieldToUninits(LocalChain.add(LocField(FR)), R);
211
28
  }
212
213
20
  IsAnyFieldInitialized = true;
214
20
  return false;
215
48
}
216
217
//===----------------------------------------------------------------------===//
218
//                           Utility functions.
219
//===----------------------------------------------------------------------===//
220
221
static std::optional<DereferenceInfo> dereference(ProgramStateRef State,
222
135
                                                  const FieldRegion *FR) {
223
224
135
  llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
225
226
135
  SVal V = State->getSVal(FR);
227
135
  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
135
  bool NeedsCastBack =
233
135
      isVoidPointer(FR->getDecl()->getType()) || 
isa<nonloc::LocAsInteger>(V)111
;
234
235
  // The region we'd like to acquire.
236
135
  const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
237
135
  if (!R)
238
22
    return std::nullopt;
239
240
113
  VisitedRegions.insert(R);
241
242
  // We acquire the dynamic type of R,
243
113
  QualType DynT = R->getLocationType();
244
245
117
  while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
246
247
18
    R = Tmp->getAs<TypedValueRegion>();
248
18
    if (!R)
249
0
      return std::nullopt;
250
251
    // We found a cyclic pointer, like int *ptr = (int *)&ptr.
252
18
    if (!VisitedRegions.insert(R).second)
253
6
      return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
254
255
12
    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.
258
12
    if (isDereferencableType(DynT->getPointeeType()))
259
8
      break;
260
12
  }
261
262
109
  
while (107
isa<CXXBaseObjectRegion>(R)) {
263
3
    NeedsCastBack = true;
264
3
    const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
265
3
    if (!SuperR)
266
1
      break;
267
268
2
    R = SuperR;
269
2
  }
270
271
107
  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
272
113
}
273
274
135
static bool isVoidPointer(QualType T) {
275
375
  while (!T.isNull()) {
276
264
    if (T->isVoidPointerType())
277
24
      return true;
278
240
    T = T->getPointeeType();
279
240
  }
280
111
  return false;
281
135
}