Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//===----- UninitializedObjectChecker.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 a checker that reports uninitialized fields in objects
10
// created after a constructor call.
11
//
12
// To read about command line options and how the checker works, refer to the
13
// top of the file and inline comments in UninitializedObject.h.
14
//
15
// Some of the logic is implemented in UninitializedPointee.cpp, to reduce the
16
// complexity of this file.
17
//
18
//===----------------------------------------------------------------------===//
19
20
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21
#include "UninitializedObject.h"
22
#include "clang/ASTMatchers/ASTMatchFinder.h"
23
#include "clang/Driver/DriverDiagnostic.h"
24
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
25
#include "clang/StaticAnalyzer/Core/Checker.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
27
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
28
29
using namespace clang;
30
using namespace clang::ento;
31
using namespace clang::ast_matchers;
32
33
/// We'll mark fields (and pointee of fields) that are confirmed to be
34
/// uninitialized as already analyzed.
35
REGISTER_SET_WITH_PROGRAMSTATE(AnalyzedRegions, const MemRegion *)
36
37
namespace {
38
39
class UninitializedObjectChecker
40
    : public Checker<check::EndFunction, check::DeadSymbols> {
41
  std::unique_ptr<BuiltinBug> BT_uninitField;
42
43
public:
44
  // The fields of this struct will be initialized when registering the checker.
45
  UninitObjCheckerOptions Opts;
46
47
  UninitializedObjectChecker()
48
11
      : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
49
50
  void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
51
  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
52
};
53
54
/// A basic field type, that is not a pointer or a reference, it's dynamic and
55
/// static type is the same.
56
class RegularField final : public FieldNode {
57
public:
58
178
  RegularField(const FieldRegion *FR) : FieldNode(FR) {}
59
60
126
  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
61
126
    Out << "uninitialized field ";
62
126
  }
63
64
156
  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
65
66
156
  virtual void printNode(llvm::raw_ostream &Out) const override {
67
156
    Out << getVariableName(getDecl());
68
156
  }
69
70
30
  virtual void printSeparator(llvm::raw_ostream &Out) const override {
71
30
    Out << '.';
72
30
  }
73
};
74
75
/// Represents that the FieldNode that comes after this is declared in a base
76
/// of the previous FieldNode. As such, this descendant doesn't wrap a
77
/// FieldRegion, and is purely a tool to describe a relation between two other
78
/// FieldRegion wrapping descendants.
79
class BaseClass final : public FieldNode {
80
  const QualType BaseClassT;
81
82
public:
83
80
  BaseClass(const QualType &T) : FieldNode(nullptr), BaseClassT(T) {
84
80
    assert(!T.isNull());
85
80
    assert(T->getAsCXXRecordDecl());
86
80
  }
87
88
0
  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
89
0
    llvm_unreachable("This node can never be the final node in the "
90
0
                     "fieldchain!");
91
0
  }
92
93
17
  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
94
95
17
  virtual void printNode(llvm::raw_ostream &Out) const override {
96
17
    Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
97
17
  }
98
99
17
  virtual void printSeparator(llvm::raw_ostream &Out) const override {}
100
101
26
  virtual bool isBase() const override { return true; }
102
};
103
104
} // end of anonymous namespace
105
106
// Utility function declarations.
107
108
/// Returns the region that was constructed by CtorDecl, or nullptr if that
109
/// isn't possible.
110
static const TypedValueRegion *
111
getConstructedRegion(const CXXConstructorDecl *CtorDecl,
112
                     CheckerContext &Context);
113
114
/// Checks whether the object constructed by \p Ctor will be analyzed later
115
/// (e.g. if the object is a field of another object, in which case we'd check
116
/// it multiple times).
117
static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
118
                                      CheckerContext &Context);
119
120
/// Checks whether RD contains a field with a name or type name that matches
121
/// \p Pattern.
122
static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern);
123
124
/// Checks _syntactically_ whether it is possible to access FD from the record
125
/// that contains it without a preceding assert (even if that access happens
126
/// inside a method). This is mainly used for records that act like unions, like
127
/// having multiple bit fields, with only a fraction being properly initialized.
128
/// If these fields are properly guarded with asserts, this method returns
129
/// false.
130
///
131
/// Since this check is done syntactically, this method could be inaccurate.
132
static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State);
133
134
//===----------------------------------------------------------------------===//
135
//                  Methods for UninitializedObjectChecker.
136
//===----------------------------------------------------------------------===//
137
138
void UninitializedObjectChecker::checkEndFunction(
139
777
    const ReturnStmt *RS, CheckerContext &Context) const {
140
777
141
777
  const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
142
777
      Context.getLocationContext()->getDecl());
143
777
  if (!CtorDecl)
144
317
    return;
145
460
146
460
  if (!CtorDecl->isUserProvided())
147
94
    return;
148
366
149
366
  if (CtorDecl->getParent()->isUnion())
150
8
    return;
151
358
152
358
  // This avoids essentially the same error being reported multiple times.
153
358
  if (willObjectBeAnalyzedLater(CtorDecl, Context))
154
47
    return;
155
311
156
311
  const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
157
311
  if (!R)
158
29
    return;
159
282
160
282
  FindUninitializedFields F(Context.getState(), R, Opts);
161
282
162
282
  std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
163
282
      F.getResults();
164
282
165
282
  ProgramStateRef UpdatedState = UninitInfo.first;
166
282
  const UninitFieldMap &UninitFields = UninitInfo.second;
167
282
168
282
  if (UninitFields.empty()) {
169
167
    Context.addTransition(UpdatedState);
170
167
    return;
171
167
  }
172
115
173
115
  // There are uninitialized fields in the record.
174
115
175
115
  ExplodedNode *Node = Context.generateNonFatalErrorNode(UpdatedState);
176
115
  if (!Node)
177
0
    return;
178
115
179
115
  PathDiagnosticLocation LocUsedForUniqueing;
180
115
  const Stmt *CallSite = Context.getStackFrame()->getCallSite();
181
115
  if (CallSite)
182
115
    LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
183
115
        CallSite, Context.getSourceManager(), Node->getLocationContext());
184
115
185
115
  // For Plist consumers that don't support notes just yet, we'll convert notes
186
115
  // to warnings.
187
115
  if (Opts.ShouldConvertNotesToWarnings) {
188
2
    for (const auto &Pair : UninitFields) {
189
2
190
2
      auto Report = llvm::make_unique<BugReport>(
191
2
          *BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
192
2
          Node->getLocationContext()->getDecl());
193
2
      Context.emitReport(std::move(Report));
194
2
    }
195
1
    return;
196
1
  }
197
114
198
114
  SmallString<100> WarningBuf;
199
114
  llvm::raw_svector_ostream WarningOS(WarningBuf);
200
114
  WarningOS << UninitFields.size() << " uninitialized field"
201
114
            << (UninitFields.size() == 1 ? 
""86
:
"s"28
)
202
114
            << " at the end of the constructor call";
203
114
204
114
  auto Report = llvm::make_unique<BugReport>(
205
114
      *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
206
114
      Node->getLocationContext()->getDecl());
207
114
208
147
  for (const auto &Pair : UninitFields) {
209
147
    Report->addNote(Pair.second,
210
147
                    PathDiagnosticLocation::create(Pair.first->getDecl(),
211
147
                                                   Context.getSourceManager()));
212
147
  }
213
114
  Context.emitReport(std::move(Report));
214
114
}
215
216
void UninitializedObjectChecker::checkDeadSymbols(SymbolReaper &SR,
217
2.25k
                                                  CheckerContext &C) const {
218
2.25k
  ProgramStateRef State = C.getState();
219
2.25k
  for (const MemRegion *R : State->get<AnalyzedRegions>()) {
220
448
    if (!SR.isLiveRegion(R))
221
274
      State = State->remove<AnalyzedRegions>(R);
222
448
  }
223
2.25k
}
224
225
//===----------------------------------------------------------------------===//
226
//                   Methods for FindUninitializedFields.
227
//===----------------------------------------------------------------------===//
228
229
FindUninitializedFields::FindUninitializedFields(
230
    ProgramStateRef State, const TypedValueRegion *const R,
231
    const UninitObjCheckerOptions &Opts)
232
282
    : State(State), ObjectR(R), Opts(Opts) {
233
282
234
282
  isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
235
282
236
282
  // In non-pedantic mode, if ObjectR doesn't contain a single initialized
237
282
  // field, we'll assume that Object was intentionally left uninitialized.
238
282
  if (!Opts.IsPedantic && 
!isAnyFieldInitialized()108
)
239
13
    UninitFields.clear();
240
282
}
241
242
bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain,
243
194
                                                const MemRegion *PointeeR) {
244
194
  const FieldRegion *FR = Chain.getUninitRegion();
245
194
246
194
  assert((PointeeR || !isDereferencableType(FR->getDecl()->getType())) &&
247
194
         "One must also pass the pointee region as a parameter for "
248
194
         "dereferenceable fields!");
249
194
250
194
  if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
251
194
          FR->getDecl()->getLocation()))
252
4
    return false;
253
190
254
190
  if (Opts.IgnoreGuardedFields && 
!hasUnguardedAccess(FR->getDecl(), State)16
)
255
14
    return false;
256
176
257
176
  if (State->contains<AnalyzedRegions>(FR))
258
6
    return false;
259
170
260
170
  if (PointeeR) {
261
44
    if (State->contains<AnalyzedRegions>(PointeeR)) {
262
4
      return false;
263
4
    }
264
40
    State = State->add<AnalyzedRegions>(PointeeR);
265
40
  }
266
170
267
170
  State = State->add<AnalyzedRegions>(FR);
268
166
269
166
  UninitFieldMap::mapped_type NoteMsgBuf;
270
166
  llvm::raw_svector_ostream OS(NoteMsgBuf);
271
166
  Chain.printNoteMsg(OS);
272
166
273
166
  return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;
274
170
}
275
276
bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
277
443
                                               FieldChainInfo LocalChain) {
278
443
  assert(R->getValueType()->isRecordType() &&
279
443
         !R->getValueType()->isUnionType() &&
280
443
         "This method only checks non-union record objects!");
281
443
282
443
  const RecordDecl *RD = R->getValueType()->getAsRecordDecl()->getDefinition();
283
443
284
443
  if (!RD) {
285
2
    IsAnyFieldInitialized = true;
286
2
    return true;
287
2
  }
288
441
289
441
  if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
290
441
      shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
291
5
    IsAnyFieldInitialized = true;
292
5
    return false;
293
5
  }
294
436
295
436
  bool ContainsUninitField = false;
296
436
297
436
  // Are all of this non-union's fields initialized?
298
662
  for (const FieldDecl *I : RD->fields()) {
299
662
300
662
    const auto FieldVal =
301
662
        State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
302
662
    const auto *FR = FieldVal.getRegionAs<FieldRegion>();
303
662
    QualType T = I->getType();
304
662
305
662
    // If LocalChain already contains FR, then we encountered a cyclic
306
662
    // reference. In this case, region FR is already under checking at an
307
662
    // earlier node in the directed tree.
308
662
    if (LocalChain.contains(FR))
309
4
      return false;
310
658
311
658
    if (T->isStructureOrClassType()) {
312
28
      if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))
313
18
        ContainsUninitField = true;
314
28
      continue;
315
28
    }
316
630
317
630
    if (T->isUnionType()) {
318
14
      if (isUnionUninit(FR)) {
319
0
        if (addFieldToUninits(LocalChain.add(RegularField(FR))))
320
0
          ContainsUninitField = true;
321
0
      } else
322
14
        IsAnyFieldInitialized = true;
323
14
      continue;
324
14
    }
325
616
326
616
    if (T->isArrayType()) {
327
4
      IsAnyFieldInitialized = true;
328
4
      continue;
329
4
    }
330
612
331
612
    SVal V = State->getSVal(FieldVal);
332
612
333
612
    if (isDereferencableType(T) || 
V.getAs<nonloc::LocAsInteger>()452
) {
334
162
      if (isDereferencableUninit(FR, LocalChain))
335
70
        ContainsUninitField = true;
336
162
      continue;
337
162
    }
338
450
339
450
    if (isPrimitiveType(T)) {
340
450
      if (isPrimitiveUninit(V)) {
341
150
        if (addFieldToUninits(LocalChain.add(RegularField(FR))))
342
126
          ContainsUninitField = true;
343
150
      }
344
450
      continue;
345
450
    }
346
0
347
0
    llvm_unreachable("All cases are handled!");
348
0
  }
349
436
350
436
  // Checking bases. The checker will regard inherited data members as direct
351
436
  // fields.
352
436
  const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
353
432
  if (!CXXRD)
354
0
    return ContainsUninitField;
355
432
356
432
  for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
357
80
    const auto *BaseRegion = State->getLValue(BaseSpec, R)
358
80
                                 .castAs<loc::MemRegionVal>()
359
80
                                 .getRegionAs<TypedValueRegion>();
360
80
361
80
    // If the head of the list is also a BaseClass, we'll overwrite it to avoid
362
80
    // note messages like 'this->A::B::x'.
363
80
    if (!LocalChain.isEmpty() && 
LocalChain.getHead().isBase()28
) {
364
26
      if (isNonUnionUninit(BaseRegion, LocalChain.replaceHead(
365
26
                                           BaseClass(BaseSpec.getType()))))
366
7
        ContainsUninitField = true;
367
54
    } else {
368
54
      if (isNonUnionUninit(BaseRegion,
369
54
                           LocalChain.add(BaseClass(BaseSpec.getType()))))
370
17
        ContainsUninitField = true;
371
54
    }
372
80
  }
373
432
374
432
  return ContainsUninitField;
375
432
}
376
377
18
bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
378
18
  assert(R->getValueType()->isUnionType() &&
379
18
         "This method only checks union objects!");
380
18
  // TODO: Implement support for union fields.
381
18
  return false;
382
18
}
383
384
492
bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
385
492
  if (V.isUndef())
386
178
    return true;
387
314
388
314
  IsAnyFieldInitialized = true;
389
314
  return false;
390
314
}
391
392
//===----------------------------------------------------------------------===//
393
//                       Methods for FieldChainInfo.
394
//===----------------------------------------------------------------------===//
395
396
662
bool FieldChainInfo::contains(const FieldRegion *FR) const {
397
662
  for (const FieldNode &Node : Chain) {
398
230
    if (Node.isSameRegion(FR))
399
4
      return true;
400
230
  }
401
662
  
return false658
;
402
662
}
403
404
/// Prints every element except the last to `Out`. Since ImmutableLists store
405
/// elements in reverse order, and have no reverse iterators, we use a
406
/// recursive function to print the fieldchain correctly. The last element in
407
/// the chain is to be printed by `FieldChainInfo::print`.
408
static void printTail(llvm::raw_ostream &Out,
409
                      const FieldChainInfo::FieldChain L);
410
411
// FIXME: This function constructs an incorrect string in the following case:
412
//
413
//   struct Base { int x; };
414
//   struct D1 : Base {}; struct D2 : Base {};
415
//
416
//   struct MostDerived : D1, D2 {
417
//     MostDerived() {}
418
//   }
419
//
420
// A call to MostDerived::MostDerived() will cause two notes that say
421
// "uninitialized field 'this->x'", but we can't refer to 'x' directly,
422
// we need an explicit namespace resolution whether the uninit field was
423
// 'D1::x' or 'D2::x'.
424
166
void FieldChainInfo::printNoteMsg(llvm::raw_ostream &Out) const {
425
166
  if (Chain.isEmpty())
426
0
    return;
427
166
428
166
  const FieldNode &LastField = getHead();
429
166
430
166
  LastField.printNoteMsg(Out);
431
166
  Out << '\'';
432
166
433
166
  for (const FieldNode &Node : Chain)
434
262
    Node.printPrefix(Out);
435
166
436
166
  Out << "this->";
437
166
  printTail(Out, Chain.getTail());
438
166
  LastField.printNode(Out);
439
166
  Out << '\'';
440
166
}
441
442
static void printTail(llvm::raw_ostream &Out,
443
262
                      const FieldChainInfo::FieldChain L) {
444
262
  if (L.isEmpty())
445
166
    return;
446
96
447
96
  printTail(Out, L.getTail());
448
96
449
96
  L.getHead().printNode(Out);
450
96
  L.getHead().printSeparator(Out);
451
96
}
452
453
//===----------------------------------------------------------------------===//
454
//                           Utility functions.
455
//===----------------------------------------------------------------------===//
456
457
static const TypedValueRegion *
458
getConstructedRegion(const CXXConstructorDecl *CtorDecl,
459
727
                     CheckerContext &Context) {
460
727
461
727
  Loc ThisLoc =
462
727
      Context.getSValBuilder().getCXXThis(CtorDecl, Context.getStackFrame());
463
727
464
727
  SVal ObjectV = Context.getState()->getSVal(ThisLoc);
465
727
466
727
  auto *R = ObjectV.getAsRegion()->getAs<TypedValueRegion>();
467
727
  if (R && 
!R->getValueType()->getAsCXXRecordDecl()660
)
468
0
    return nullptr;
469
727
470
727
  return R;
471
727
}
472
473
static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
474
358
                                      CheckerContext &Context) {
475
358
476
358
  const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
477
358
  if (!CurrRegion)
478
29
    return false;
479
329
480
329
  const LocationContext *LC = Context.getLocationContext();
481
613
  while ((LC = LC->getParent())) {
482
331
483
331
    // If \p Ctor was called by another constructor.
484
331
    const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(LC->getDecl());
485
331
    if (!OtherCtor)
486
273
      continue;
487
58
488
58
    const TypedValueRegion *OtherRegion =
489
58
        getConstructedRegion(OtherCtor, Context);
490
58
    if (!OtherRegion)
491
9
      continue;
492
49
493
49
    // If the CurrRegion is a subregion of OtherRegion, it will be analyzed
494
49
    // during the analysis of OtherRegion.
495
49
    if (CurrRegion->isSubRegionOf(OtherRegion))
496
47
      return true;
497
49
  }
498
329
499
329
  
return false282
;
500
329
}
501
502
441
static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
503
441
  llvm::Regex R(Pattern);
504
441
505
669
  for (const FieldDecl *FD : RD->fields()) {
506
669
    if (R.match(FD->getType().getAsString()))
507
4
      return true;
508
665
    if (R.match(FD->getName()))
509
1
      return true;
510
665
  }
511
441
512
441
  
return false436
;
513
441
}
514
515
75
static const Stmt *getMethodBody(const CXXMethodDecl *M) {
516
75
  if (isa<CXXConstructorDecl>(M))
517
43
    return nullptr;
518
32
519
32
  if (!M->isDefined())
520
2
    return nullptr;
521
30
522
30
  return M->getDefinition()->getBody();
523
30
}
524
525
16
static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State) {
526
16
527
16
  if (FD->getAccess() == AccessSpecifier::AS_public)
528
1
    return true;
529
15
530
15
  const auto *Parent = dyn_cast<CXXRecordDecl>(FD->getParent());
531
15
532
15
  if (!Parent)
533
0
    return true;
534
15
535
15
  Parent = Parent->getDefinition();
536
15
  assert(Parent && "The record's definition must be avaible if an uninitialized"
537
15
                   " field of it was found!");
538
15
539
15
  ASTContext &AC = State->getStateManager().getContext();
540
15
541
15
  auto FieldAccessM = memberExpr(hasDeclaration(equalsNode(FD))).bind("access");
542
15
543
15
  auto AssertLikeM = callExpr(callee(functionDecl(
544
15
      anyOf(hasName("exit"), hasName("panic"), hasName("error"),
545
15
            hasName("Assert"), hasName("assert"), hasName("ziperr"),
546
15
            hasName("assfail"), hasName("db_error"), hasName("__assert"),
547
15
            hasName("__assert2"), hasName("_wassert"), hasName("__assert_rtn"),
548
15
            hasName("__assert_fail"), hasName("dtrace_assfail"),
549
15
            hasName("yy_fatal_error"), hasName("_XCAssertionFailureHandler"),
550
15
            hasName("_DTAssertionFailureHandler"),
551
15
            hasName("_TSAssertionFailureHandler")))));
552
15
553
15
  auto NoReturnFuncM = callExpr(callee(functionDecl(isNoReturn())));
554
15
555
15
  auto GuardM =
556
15
      stmt(anyOf(ifStmt(), switchStmt(), conditionalOperator(), AssertLikeM,
557
15
            NoReturnFuncM))
558
15
          .bind("guard");
559
15
560
75
  for (const CXXMethodDecl *M : Parent->methods()) {
561
75
    const Stmt *MethodBody = getMethodBody(M);
562
75
    if (!MethodBody)
563
45
      continue;
564
30
565
30
    auto Accesses = match(stmt(hasDescendant(FieldAccessM)), *MethodBody, AC);
566
30
    if (Accesses.empty())
567
15
      continue;
568
15
    const auto *FirstAccess = Accesses[0].getNodeAs<MemberExpr>("access");
569
15
    assert(FirstAccess);
570
15
571
15
    auto Guards = match(stmt(hasDescendant(GuardM)), *MethodBody, AC);
572
15
    if (Guards.empty())
573
1
      return true;
574
14
    const auto *FirstGuard = Guards[0].getNodeAs<Stmt>("guard");
575
14
    assert(FirstGuard);
576
14
577
14
    if (FirstAccess->getBeginLoc() < FirstGuard->getBeginLoc())
578
0
      return true;
579
14
  }
580
15
581
15
  
return false14
;
582
15
}
583
584
245
std::string clang::ento::getVariableName(const FieldDecl *Field) {
585
245
  // If Field is a captured lambda variable, Field->getName() will return with
586
245
  // an empty string. We can however acquire it's name from the lambda's
587
245
  // captures.
588
245
  const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
589
245
590
245
  if (CXXParent && CXXParent->isLambda()) {
591
14
    assert(CXXParent->captures_begin());
592
14
    auto It = CXXParent->captures_begin() + Field->getFieldIndex();
593
14
594
14
    if (It->capturesVariable())
595
12
      return llvm::Twine("/*captured variable*/" +
596
12
                         It->getCapturedVar()->getName())
597
12
          .str();
598
2
599
2
    if (It->capturesThis())
600
2
      return "/*'this' capture*/";
601
0
602
0
    llvm_unreachable("No other capture type is expected!");
603
0
  }
604
231
605
231
  return Field->getName();
606
231
}
607
608
11
void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
609
11
  auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
610
11
611
11
  AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
612
11
  UninitObjCheckerOptions &ChOpts = Chk->Opts;
613
11
614
11
  ChOpts.IsPedantic = AnOpts.getCheckerBooleanOption(Chk, "Pedantic");
615
11
  ChOpts.ShouldConvertNotesToWarnings = AnOpts.getCheckerBooleanOption(
616
11
      Chk, "NotesAsWarnings");
617
11
  ChOpts.CheckPointeeInitialization = AnOpts.getCheckerBooleanOption(
618
11
      Chk, "CheckPointeeInitialization");
619
11
  ChOpts.IgnoredRecordsWithFieldPattern =
620
11
      AnOpts.getCheckerStringOption(Chk, "IgnoreRecordsWithField");
621
11
  ChOpts.IgnoreGuardedFields =
622
11
      AnOpts.getCheckerBooleanOption(Chk, "IgnoreGuardedFields");
623
11
624
11
  std::string ErrorMsg;
625
11
  if (!llvm::Regex(ChOpts.IgnoredRecordsWithFieldPattern).isValid(ErrorMsg))
626
1
    Mgr.reportInvalidCheckerOptionValue(Chk, "IgnoreRecordsWithField",
627
1
        "a valid regex, building failed with error message "
628
1
        "\"" + ErrorMsg + "\"");
629
11
}
630
631
11
bool ento::shouldRegisterUninitializedObjectChecker(const LangOptions &LO) {
632
11
  return true;
633
11
}