Coverage Report

Created: 2020-09-22 08:39

/Users/buildslave/jenkins/workspace/coverage/llvm-project/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/DynamicType.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
13
      : 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
861
    const ReturnStmt *RS, CheckerContext &Context) const {
140
141
861
  const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
142
861
      Context.getLocationContext()->getDecl());
143
861
  if (!CtorDecl)
144
367
    return;
145
146
494
  if (!CtorDecl->isUserProvided())
147
128
    return;
148
149
366
  if (CtorDecl->getParent()->isUnion())
150
8
    return;
151
152
  // This avoids essentially the same error being reported multiple times.
153
358
  if (willObjectBeAnalyzedLater(CtorDecl, Context))
154
47
    return;
155
156
311
  const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
157
311
  if (!R)
158
29
    return;
159
160
282
  FindUninitializedFields F(Context.getState(), R, Opts);
161
162
282
  std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
163
282
      F.getResults();
164
165
282
  ProgramStateRef UpdatedState = UninitInfo.first;
166
282
  const UninitFieldMap &UninitFields = UninitInfo.second;
167
168
282
  if (UninitFields.empty()) {
169
167
    Context.addTransition(UpdatedState);
170
167
    return;
171
167
  }
172
173
  // There are uninitialized fields in the record.
174
175
115
  ExplodedNode *Node = Context.generateNonFatalErrorNode(UpdatedState);
176
115
  if (!Node)
177
0
    return;
178
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
185
  // For Plist consumers that don't support notes just yet, we'll convert notes
186
  // to warnings.
187
115
  if (Opts.ShouldConvertNotesToWarnings) {
188
2
    for (const auto &Pair : UninitFields) {
189
190
2
      auto Report = std::make_unique<PathSensitiveBugReport>(
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
198
114
  SmallString<100> WarningBuf;
199
114
  llvm::raw_svector_ostream WarningOS(WarningBuf);
200
114
  WarningOS << UninitFields.size() << " uninitialized field"
201
86
            << (UninitFields.size() == 1 ? "" : 
"s"28
)
202
114
            << " at the end of the constructor call";
203
204
114
  auto Report = std::make_unique<PathSensitiveBugReport>(
205
114
      *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
206
114
      Node->getLocationContext()->getDecl());
207
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.49k
                                                  CheckerContext &C) const {
218
2.49k
  ProgramStateRef State = C.getState();
219
448
  for (const MemRegion *R : State->get<AnalyzedRegions>()) {
220
448
    if (!SR.isLiveRegion(R))
221
274
      State = State->remove<AnalyzedRegions>(R);
222
448
  }
223
2.49k
}
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
234
282
  isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
235
236
  // In non-pedantic mode, if ObjectR doesn't contain a single initialized
237
  // 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
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
250
194
  if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
251
194
          FR->getDecl()->getLocation()))
252
4
    return false;
253
254
190
  if (Opts.IgnoreGuardedFields && 
!hasUnguardedAccess(FR->getDecl(), State)16
)
255
14
    return false;
256
257
176
  if (State->contains<AnalyzedRegions>(FR))
258
6
    return false;
259
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
267
166
  State = State->add<AnalyzedRegions>(FR);
268
269
166
  UninitFieldMap::mapped_type NoteMsgBuf;
270
166
  llvm::raw_svector_ostream OS(NoteMsgBuf);
271
166
  Chain.printNoteMsg(OS);
272
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
282
443
  const RecordDecl *RD = R->getValueType()->getAsRecordDecl()->getDefinition();
283
284
443
  if (!RD) {
285
2
    IsAnyFieldInitialized = true;
286
2
    return true;
287
2
  }
288
289
441
  if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
290
441
      shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
291
5
    IsAnyFieldInitialized = true;
292
5
    return false;
293
5
  }
294
295
436
  bool ContainsUninitField = false;
296
297
  // Are all of this non-union's fields initialized?
298
662
  for (const FieldDecl *I : RD->fields()) {
299
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
305
    // If LocalChain already contains FR, then we encountered a cyclic
306
    // reference. In this case, region FR is already under checking at an
307
    // earlier node in the directed tree.
308
662
    if (LocalChain.contains(FR))
309
4
      return false;
310
311
658
    if (T->isStructureOrClassType()) {
312
28
      if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))
313
18
        ContainsUninitField = true;
314
28
      continue;
315
28
    }
316
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
326
616
    if (T->isArrayType()) {
327
4
      IsAnyFieldInitialized = true;
328
4
      continue;
329
4
    }
330
331
612
    SVal V = State->getSVal(FieldVal);
332
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
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
347
0
    llvm_unreachable("All cases are handled!");
348
0
  }
349
350
  // Checking bases. The checker will regard inherited data members as direct
351
  // fields.
352
432
  const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
353
432
  if (!CXXRD)
354
0
    return ContainsUninitField;
355
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
361
    // If the head of the list is also a BaseClass, we'll overwrite it to avoid
362
    // 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
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
  // 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
388
314
  IsAnyFieldInitialized = true;
389
314
  return false;
390
314
}
391
392
//===----------------------------------------------------------------------===//
393
//                       Methods for FieldChainInfo.
394
//===----------------------------------------------------------------------===//
395
396
1.01k
bool FieldChainInfo::contains(const FieldRegion *FR) const {
397
356
  for (const FieldNode &Node : Chain) {
398
356
    if (Node.isSameRegion(FR))
399
4
      return true;
400
356
  }
401
1.01k
  return false;
402
1.01k
}
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
428
166
  const FieldNode &LastField = getHead();
429
430
166
  LastField.printNoteMsg(Out);
431
166
  Out << '\'';
432
433
166
  for (const FieldNode &Node : Chain)
434
262
    Node.printPrefix(Out);
435
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
447
96
  printTail(Out, L.getTail());
448
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
461
727
  Loc ThisLoc =
462
727
      Context.getSValBuilder().getCXXThis(CtorDecl, Context.getStackFrame());
463
464
727
  SVal ObjectV = Context.getState()->getSVal(ThisLoc);
465
466
727
  auto *R = ObjectV.getAsRegion()->getAs<TypedValueRegion>();
467
727
  if (R && 
!R->getValueType()->getAsCXXRecordDecl()660
)
468
0
    return nullptr;
469
470
727
  return R;
471
727
}
472
473
static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
474
358
                                      CheckerContext &Context) {
475
476
358
  const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
477
358
  if (!CurrRegion)
478
29
    return false;
479
480
329
  const LocationContext *LC = Context.getLocationContext();
481
613
  while ((LC = LC->getParent())) {
482
483
    // 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
488
58
    const TypedValueRegion *OtherRegion =
489
58
        getConstructedRegion(OtherCtor, Context);
490
58
    if (!OtherRegion)
491
9
      continue;
492
493
    // If the CurrRegion is a subregion of OtherRegion, it will be analyzed
494
    // during the analysis of OtherRegion.
495
49
    if (CurrRegion->isSubRegionOf(OtherRegion))
496
47
      return true;
497
49
  }
498
499
282
  return false;
500
329
}
501
502
441
static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
503
441
  llvm::Regex R(Pattern);
504
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
512
436
  return false;
513
441
}
514
515
75
static const Stmt *getMethodBody(const CXXMethodDecl *M) {
516
75
  if (isa<CXXConstructorDecl>(M))
517
43
    return nullptr;
518
519
32
  if (!M->isDefined())
520
2
    return nullptr;
521
522
30
  return M->getDefinition()->getBody();
523
30
}
524
525
16
static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State) {
526
527
16
  if (FD->getAccess() == AccessSpecifier::AS_public)
528
1
    return true;
529
530
15
  const auto *Parent = dyn_cast<CXXRecordDecl>(FD->getParent());
531
532
15
  if (!Parent)
533
0
    return true;
534
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
539
15
  ASTContext &AC = State->getStateManager().getContext();
540
541
15
  auto FieldAccessM = memberExpr(hasDeclaration(equalsNode(FD))).bind("access");
542
543
15
  auto AssertLikeM = callExpr(callee(functionDecl(
544
15
      hasAnyName("exit", "panic", "error", "Assert", "assert", "ziperr",
545
15
                 "assfail", "db_error", "__assert", "__assert2", "_wassert",
546
15
                 "__assert_rtn", "__assert_fail", "dtrace_assfail",
547
15
                 "yy_fatal_error", "_XCAssertionFailureHandler",
548
15
                 "_DTAssertionFailureHandler", "_TSAssertionFailureHandler"))));
549
550
15
  auto NoReturnFuncM = callExpr(callee(functionDecl(isNoReturn())));
551
552
15
  auto GuardM =
553
15
      stmt(anyOf(ifStmt(), switchStmt(), conditionalOperator(), AssertLikeM,
554
15
            NoReturnFuncM))
555
15
          .bind("guard");
556
557
75
  for (const CXXMethodDecl *M : Parent->methods()) {
558
75
    const Stmt *MethodBody = getMethodBody(M);
559
75
    if (!MethodBody)
560
45
      continue;
561
562
30
    auto Accesses = match(stmt(hasDescendant(FieldAccessM)), *MethodBody, AC);
563
30
    if (Accesses.empty())
564
15
      continue;
565
15
    const auto *FirstAccess = Accesses[0].getNodeAs<MemberExpr>("access");
566
15
    assert(FirstAccess);
567
568
15
    auto Guards = match(stmt(hasDescendant(GuardM)), *MethodBody, AC);
569
15
    if (Guards.empty())
570
1
      return true;
571
14
    const auto *FirstGuard = Guards[0].getNodeAs<Stmt>("guard");
572
14
    assert(FirstGuard);
573
574
14
    if (FirstAccess->getBeginLoc() < FirstGuard->getBeginLoc())
575
0
      return true;
576
14
  }
577
578
14
  return false;
579
15
}
580
581
245
std::string clang::ento::getVariableName(const FieldDecl *Field) {
582
  // If Field is a captured lambda variable, Field->getName() will return with
583
  // an empty string. We can however acquire it's name from the lambda's
584
  // captures.
585
245
  const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
586
587
245
  if (CXXParent && CXXParent->isLambda()) {
588
14
    assert(CXXParent->captures_begin());
589
14
    auto It = CXXParent->captures_begin() + Field->getFieldIndex();
590
591
14
    if (It->capturesVariable())
592
12
      return llvm::Twine("/*captured variable*/" +
593
12
                         It->getCapturedVar()->getName())
594
12
          .str();
595
596
2
    if (It->capturesThis())
597
2
      return "/*'this' capture*/";
598
599
0
    llvm_unreachable("No other capture type is expected!");
600
0
  }
601
602
231
  return std::string(Field->getName());
603
231
}
604
605
13
void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
606
13
  auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
607
608
13
  const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
609
13
  UninitObjCheckerOptions &ChOpts = Chk->Opts;
610
611
13
  ChOpts.IsPedantic = AnOpts.getCheckerBooleanOption(Chk, "Pedantic");
612
13
  ChOpts.ShouldConvertNotesToWarnings = AnOpts.getCheckerBooleanOption(
613
13
      Chk, "NotesAsWarnings");
614
13
  ChOpts.CheckPointeeInitialization = AnOpts.getCheckerBooleanOption(
615
13
      Chk, "CheckPointeeInitialization");
616
13
  ChOpts.IgnoredRecordsWithFieldPattern =
617
13
      std::string(AnOpts.getCheckerStringOption(Chk, "IgnoreRecordsWithField"));
618
13
  ChOpts.IgnoreGuardedFields =
619
13
      AnOpts.getCheckerBooleanOption(Chk, "IgnoreGuardedFields");
620
621
13
  std::string ErrorMsg;
622
13
  if (!llvm::Regex(ChOpts.IgnoredRecordsWithFieldPattern).isValid(ErrorMsg))
623
1
    Mgr.reportInvalidCheckerOptionValue(Chk, "IgnoreRecordsWithField",
624
1
        "a valid regex, building failed with error message "
625
1
        "\"" + ErrorMsg + "\"");
626
13
}
627
628
26
bool ento::shouldRegisterUninitializedObjectChecker(const CheckerManager &mgr) {
629
26
  return true;
630
26
}