blob: 016be6fed8b8628d6bd37bd3d95b188312965560 [file] [log] [blame]
Kristof Umann30f08652018-06-18 11:50:17 +00001//===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a checker that reports uninitialized fields in objects
11// created after a constructor call.
12//
Kristof Umann9bd44392018-06-29 11:25:24 +000013// This checker has two options:
14// - "Pedantic" (boolean). If its not set or is set to false, the checker
15// won't emit warnings for objects that don't have at least one initialized
16// field. This may be set with
17//
18// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
19//
20// - "NotesAsWarnings" (boolean). If set to true, the checker will emit a
21// warning for each uninitalized field, as opposed to emitting one warning
22// per constructor call, and listing the uninitialized fields that belongs
23// to it in notes. Defaults to false.
24//
25// `-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
Kristof Umann30f08652018-06-18 11:50:17 +000026//
27//===----------------------------------------------------------------------===//
28
29#include "ClangSACheckers.h"
30#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
31#include "clang/StaticAnalyzer/Core/Checker.h"
32#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
33#include <algorithm>
34
35using namespace clang;
36using namespace clang::ento;
37
38namespace {
39
40class UninitializedObjectChecker : public Checker<check::EndFunction> {
41 std::unique_ptr<BuiltinBug> BT_uninitField;
42
43public:
Kristof Umann9bd44392018-06-29 11:25:24 +000044 // These fields will be initialized when registering the checker.
45 bool IsPedantic;
46 bool ShouldConvertNotesToWarnings;
Kristof Umann30f08652018-06-18 11:50:17 +000047
48 UninitializedObjectChecker()
49 : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
50 void checkEndFunction(CheckerContext &C) const;
51};
52
Kristof Umann30f08652018-06-18 11:50:17 +000053/// Represents a field chain. A field chain is a vector of fields where the
54/// first element of the chain is the object under checking (not stored), and
55/// every other element is a field, and the element that precedes it is the
56/// object that contains it.
57///
58/// Note that this class is immutable, and new fields may only be added through
59/// constructor calls.
60class FieldChainInfo {
61 using FieldChain = llvm::ImmutableList<const FieldRegion *>;
62
63 FieldChain Chain;
64
65 const bool IsDereferenced = false;
66
67public:
68 FieldChainInfo() = default;
69
70 FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
71 : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
72
73 FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
74 const bool IsDereferenced = false);
75
76 bool contains(const FieldRegion *FR) const { return Chain.contains(FR); }
77 bool isPointer() const;
78
79 /// If this is a fieldchain whose last element is an uninitialized region of a
80 /// pointer type, `IsDereferenced` will store whether the pointer itself or
81 /// the pointee is uninitialized.
82 bool isDereferenced() const;
83 const FieldDecl *getEndOfChain() const;
84 void print(llvm::raw_ostream &Out) const;
85
86private:
87 /// Prints every element except the last to `Out`. Since ImmutableLists store
88 /// elements in reverse order, and have no reverse iterators, we use a
89 /// recursive function to print the fieldchain correctly. The last element in
90 /// the chain is to be printed by `print`.
91 static void printTail(llvm::raw_ostream &Out,
92 const llvm::ImmutableListImpl<const FieldRegion *> *L);
93 friend struct FieldChainInfoComparator;
94};
95
96struct FieldChainInfoComparator {
Steven Wub3684db2018-06-22 16:51:17 +000097 bool operator()(const FieldChainInfo &lhs, const FieldChainInfo &rhs) const {
Kristof Umann30f08652018-06-18 11:50:17 +000098 assert(!lhs.Chain.isEmpty() && !rhs.Chain.isEmpty() &&
99 "Attempted to store an empty fieldchain!");
100 return *lhs.Chain.begin() < *rhs.Chain.begin();
101 }
102};
103
104using UninitFieldSet = std::set<FieldChainInfo, FieldChainInfoComparator>;
105
106/// Searches for and stores uninitialized fields in a non-union object.
107class FindUninitializedFields {
108 ProgramStateRef State;
109 const TypedValueRegion *const ObjectR;
110
111 const bool IsPedantic;
112 bool IsAnyFieldInitialized = false;
113
114 UninitFieldSet UninitFields;
115
116public:
117 FindUninitializedFields(ProgramStateRef State,
118 const TypedValueRegion *const R, bool IsPedantic);
119 const UninitFieldSet &getUninitFields();
120
121private:
122 /// Adds a FieldChainInfo object to UninitFields. Return true if an insertion
123 /// took place.
124 bool addFieldToUninits(FieldChainInfo LocalChain);
125
126 // For the purposes of this checker, we'll regard the object under checking as
127 // a directed tree, where
128 // * the root is the object under checking
129 // * every node is an object that is
130 // - a union
131 // - a non-union record
132 // - a pointer/reference
133 // - an array
134 // - of a member pointer type
135 // - of a primitive type, which we'll define as either a BuiltinType or
136 // EnumeralType.
137 // * the parent of each node is the object that contains it
138 // * every leaf is an array, a primitive object, a member pointer, a nullptr
139 // or an undefined pointer.
140 //
141 // Example:
142 //
143 // struct A {
144 // struct B {
145 // int x, y = 0;
146 // };
147 // B b;
148 // int *iptr = new int;
149 // B* bptr;
150 //
151 // A() {}
152 // };
153 //
154 // The directed tree:
155 //
156 // ->x
157 // /
158 // ->b--->y
159 // /
160 // A-->iptr->(int value)
161 // \
162 // ->bptr
163 //
164 // From this we'll construct a vector of fieldchains, where each fieldchain
165 // represents an uninitialized field. An uninitialized field may be a
166 // primitive object, a member pointer, a pointer, a pointee or a union without
167 // a single initialized field.
168 // In the above example, for the default constructor call we'll end up with
169 // these fieldchains:
170 //
171 // this->b.x
172 // this->iptr (pointee uninit)
173 // this->bptr (pointer uninit)
174 //
175 // We'll traverse each node of the above graph with the appropiate one of
176 // these methods:
177
178 /// This method checks a region of a union object, and returns true if no
179 /// field is initialized within the region.
180 bool isUnionUninit(const TypedValueRegion *R);
181
182 /// This method checks a region of a non-union object, and returns true if
183 /// an uninitialized field is found within the region.
184 bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
185
186 /// This method checks a region of a pointer or reference object, and returns
187 /// true if the ptr/ref object itself or any field within the pointee's region
188 /// is uninitialized.
189 bool isPointerOrReferenceUninit(const FieldRegion *FR,
190 FieldChainInfo LocalChain);
191
192 /// This method checks a region of MemberPointerType, and returns true if the
193 /// the pointer is uninitialized.
194 bool isMemberPointerUninit(const FieldRegion *FR, FieldChainInfo LocalChain);
195
196 /// This method returns true if the value of a primitive object is
197 /// uninitialized.
198 bool isPrimitiveUninit(const SVal &V);
199
200 // Note that we don't have a method for arrays -- the elements of an array are
201 // often left uninitialized intentionally even when it is of a C++ record
202 // type, so we'll assume that an array is always initialized.
203 // TODO: Add a support for nonloc::LocAsInteger.
204};
205
Kristof Umanncc852442018-07-12 13:13:46 +0000206} // end of anonymous namespace
207
208// Static variable instantionations.
209
210static llvm::ImmutableListFactory<const FieldRegion *> Factory;
211
Kristof Umann30f08652018-06-18 11:50:17 +0000212// Utility function declarations.
213
214/// Returns the object that was constructed by CtorDecl, or None if that isn't
215/// possible.
Kristof Umanncc852442018-07-12 13:13:46 +0000216static Optional<nonloc::LazyCompoundVal>
Kristof Umann30f08652018-06-18 11:50:17 +0000217getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
218
219/// Checks whether the constructor under checking is called by another
220/// constructor.
Kristof Umanncc852442018-07-12 13:13:46 +0000221static bool isCalledByConstructor(const CheckerContext &Context);
Kristof Umann30f08652018-06-18 11:50:17 +0000222
223/// Returns whether FD can be (transitively) dereferenced to a void pointer type
224/// (void*, void**, ...). The type of the region behind a void pointer isn't
225/// known, and thus FD can not be analyzed.
Kristof Umanncc852442018-07-12 13:13:46 +0000226static bool isVoidPointer(const FieldDecl *FD);
Kristof Umann30f08652018-06-18 11:50:17 +0000227
228/// Returns true if T is a primitive type. We'll call a type primitive if it's
229/// either a BuiltinType or an EnumeralType.
Kristof Umanncc852442018-07-12 13:13:46 +0000230static bool isPrimitiveType(const QualType &T) {
Kristof Umann30f08652018-06-18 11:50:17 +0000231 return T->isBuiltinType() || T->isEnumeralType();
232}
233
Kristof Umann9bd44392018-06-29 11:25:24 +0000234/// Constructs a note message for a given FieldChainInfo object.
Kristof Umanncc852442018-07-12 13:13:46 +0000235static void printNoteMessage(llvm::raw_ostream &Out,
236 const FieldChainInfo &Chain);
Kristof Umann30f08652018-06-18 11:50:17 +0000237
238//===----------------------------------------------------------------------===//
239// Methods for UninitializedObjectChecker.
240//===----------------------------------------------------------------------===//
241
242void UninitializedObjectChecker::checkEndFunction(
243 CheckerContext &Context) const {
244
245 const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
246 Context.getLocationContext()->getDecl());
247 if (!CtorDecl)
248 return;
249
250 if (!CtorDecl->isUserProvided())
251 return;
252
253 if (CtorDecl->getParent()->isUnion())
254 return;
255
256 // This avoids essentially the same error being reported multiple times.
257 if (isCalledByConstructor(Context))
258 return;
259
260 Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context);
261 if (!Object)
262 return;
263
264 FindUninitializedFields F(Context.getState(), Object->getRegion(),
265 IsPedantic);
266
267 const UninitFieldSet &UninitFields = F.getUninitFields();
268
269 if (UninitFields.empty())
270 return;
271
272 // There are uninitialized fields in the record.
273
274 ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
275 if (!Node)
276 return;
277
278 PathDiagnosticLocation LocUsedForUniqueing;
279 const Stmt *CallSite = Context.getStackFrame()->getCallSite();
280 if (CallSite)
281 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
282 CallSite, Context.getSourceManager(), Node->getLocationContext());
283
Kristof Umann9bd44392018-06-29 11:25:24 +0000284 // For Plist consumers that don't support notes just yet, we'll convert notes
285 // to warnings.
286 if (ShouldConvertNotesToWarnings) {
287 for (const auto &Chain : UninitFields) {
288 SmallString<100> WarningBuf;
289 llvm::raw_svector_ostream WarningOS(WarningBuf);
290
291 printNoteMessage(WarningOS, Chain);
292
293 auto Report = llvm::make_unique<BugReport>(
294 *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
295 Node->getLocationContext()->getDecl());
296 Context.emitReport(std::move(Report));
297 }
298 return;
299 }
300
Kristof Umann30f08652018-06-18 11:50:17 +0000301 SmallString<100> WarningBuf;
302 llvm::raw_svector_ostream WarningOS(WarningBuf);
303 WarningOS << UninitFields.size() << " uninitialized field"
304 << (UninitFields.size() == 1 ? "" : "s")
305 << " at the end of the constructor call";
306
307 auto Report = llvm::make_unique<BugReport>(
308 *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
309 Node->getLocationContext()->getDecl());
310
Kristof Umann9bd44392018-06-29 11:25:24 +0000311 for (const auto &Chain : UninitFields) {
Kristof Umann30f08652018-06-18 11:50:17 +0000312 SmallString<200> NoteBuf;
313 llvm::raw_svector_ostream NoteOS(NoteBuf);
314
Kristof Umann9bd44392018-06-29 11:25:24 +0000315 printNoteMessage(NoteOS, Chain);
Kristof Umann30f08652018-06-18 11:50:17 +0000316
317 Report->addNote(NoteOS.str(),
Kristof Umann9bd44392018-06-29 11:25:24 +0000318 PathDiagnosticLocation::create(Chain.getEndOfChain(),
Kristof Umann30f08652018-06-18 11:50:17 +0000319 Context.getSourceManager()));
320 }
Kristof Umann30f08652018-06-18 11:50:17 +0000321 Context.emitReport(std::move(Report));
322}
323
324//===----------------------------------------------------------------------===//
325// Methods for FindUninitializedFields.
326//===----------------------------------------------------------------------===//
327
328FindUninitializedFields::FindUninitializedFields(
329 ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic)
330 : State(State), ObjectR(R), IsPedantic(IsPedantic) {}
331
332const UninitFieldSet &FindUninitializedFields::getUninitFields() {
333 isNonUnionUninit(ObjectR, FieldChainInfo());
334
335 if (!IsPedantic && !IsAnyFieldInitialized)
336 UninitFields.clear();
337
338 return UninitFields;
339}
340
341bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
342 if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
343 Chain.getEndOfChain()->getLocation()))
344 return false;
345
346 return UninitFields.insert(Chain).second;
347}
348
349bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
350 FieldChainInfo LocalChain) {
351 assert(R->getValueType()->isRecordType() &&
352 !R->getValueType()->isUnionType() &&
353 "This method only checks non-union record objects!");
354
355 const RecordDecl *RD =
356 R->getValueType()->getAs<RecordType>()->getDecl()->getDefinition();
357 assert(RD && "Referred record has no definition");
358
359 bool ContainsUninitField = false;
360
361 // Are all of this non-union's fields initialized?
362 for (const FieldDecl *I : RD->fields()) {
363
364 const auto FieldVal =
365 State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
366 const auto *FR = FieldVal.getRegionAs<FieldRegion>();
367 QualType T = I->getType();
368
369 // If LocalChain already contains FR, then we encountered a cyclic
370 // reference. In this case, region FR is already under checking at an
371 // earlier node in the directed tree.
372 if (LocalChain.contains(FR))
373 return false;
374
375 if (T->isStructureOrClassType()) {
376 if (isNonUnionUninit(FR, {LocalChain, FR}))
377 ContainsUninitField = true;
378 continue;
379 }
380
381 if (T->isUnionType()) {
382 if (isUnionUninit(FR)) {
383 if (addFieldToUninits({LocalChain, FR}))
384 ContainsUninitField = true;
385 } else
386 IsAnyFieldInitialized = true;
387 continue;
388 }
389
390 if (T->isArrayType()) {
391 IsAnyFieldInitialized = true;
392 continue;
393 }
394
395 if (T->isMemberPointerType()) {
396 if (isMemberPointerUninit(FR, LocalChain))
397 ContainsUninitField = true;
398 continue;
399 }
400
401 // If this is a pointer or reference type.
402 if (T->isPointerType() || T->isReferenceType()) {
403 if (isPointerOrReferenceUninit(FR, LocalChain))
404 ContainsUninitField = true;
405 continue;
406 }
407
Kristof Umann20e85ba2018-06-19 08:35:02 +0000408 if (isPrimitiveType(T)) {
409 SVal V = State->getSVal(FieldVal);
Kristof Umann30f08652018-06-18 11:50:17 +0000410
Kristof Umann20e85ba2018-06-19 08:35:02 +0000411 if (isPrimitiveUninit(V)) {
412 if (addFieldToUninits({LocalChain, FR}))
413 ContainsUninitField = true;
414 }
415 continue;
Kristof Umann30f08652018-06-18 11:50:17 +0000416 }
Kristof Umann20e85ba2018-06-19 08:35:02 +0000417
418 llvm_unreachable("All cases are handled!");
Kristof Umann30f08652018-06-18 11:50:17 +0000419 }
420
421 // Checking bases.
422 // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
423 // is a descendant of another type will emit warnings for uninitalized
424 // inherited members.
425 // This is not the only way to analyze bases of an object -- if we didn't
426 // filter them out, and didn't analyze the bases, this checker would run for
427 // each base of the object in order of base initailization and in theory would
428 // find every uninitalized field. This approach could also make handling
429 // diamond inheritances more easily.
430 //
431 // This rule (that a descendant type's cunstructor is responsible for
432 // initializing inherited data members) is not obvious, and should it should
433 // be.
434 const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
435 if (!CXXRD)
436 return ContainsUninitField;
437
438 for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
439 const auto *BaseRegion = State->getLValue(BaseSpec, R)
440 .castAs<loc::MemRegionVal>()
441 .getRegionAs<TypedValueRegion>();
442
443 if (isNonUnionUninit(BaseRegion, LocalChain))
444 ContainsUninitField = true;
445 }
446
447 return ContainsUninitField;
448}
449
450bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
451 assert(R->getValueType()->isUnionType() &&
452 "This method only checks union objects!");
453 // TODO: Implement support for union fields.
454 return false;
455}
456
457// Note that pointers/references don't contain fields themselves, so in this
458// function we won't add anything to LocalChain.
459bool FindUninitializedFields::isPointerOrReferenceUninit(
460 const FieldRegion *FR, FieldChainInfo LocalChain) {
461
462 assert((FR->getDecl()->getType()->isPointerType() ||
463 FR->getDecl()->getType()->isReferenceType()) &&
464 "This method only checks pointer/reference objects!");
465
466 SVal V = State->getSVal(FR);
467
468 if (V.isUnknown() || V.isZeroConstant()) {
469 IsAnyFieldInitialized = true;
470 return false;
471 }
472
473 if (V.isUndef()) {
474 return addFieldToUninits({LocalChain, FR});
475 }
476
477 const FieldDecl *FD = FR->getDecl();
478
479 // TODO: The dynamic type of a void pointer may be retrieved with
480 // `getDynamicTypeInfo`.
481 if (isVoidPointer(FD)) {
482 IsAnyFieldInitialized = true;
483 return false;
484 }
485
486 assert(V.getAs<Loc>() && "V should be Loc at this point!");
487
488 // At this point the pointer itself is initialized and points to a valid
489 // location, we'll now check the pointee.
490 SVal DerefdV = State->getSVal(V.castAs<Loc>());
491
492 // TODO: Dereferencing should be done according to the dynamic type.
493 while (Optional<Loc> L = DerefdV.getAs<Loc>()) {
494 DerefdV = State->getSVal(*L);
495 }
496
497 // If V is a pointer pointing to a record type.
498 if (Optional<nonloc::LazyCompoundVal> RecordV =
499 DerefdV.getAs<nonloc::LazyCompoundVal>()) {
500
501 const TypedValueRegion *R = RecordV->getRegion();
502
503 // We can't reason about symbolic regions, assume its initialized.
504 // Note that this also avoids a potential infinite recursion, because
505 // constructors for list-like classes are checked without being called, and
506 // the Static Analyzer will construct a symbolic region for Node *next; or
507 // similar code snippets.
508 if (R->getSymbolicBase()) {
509 IsAnyFieldInitialized = true;
510 return false;
511 }
512
513 const QualType T = R->getValueType();
514
515 if (T->isStructureOrClassType())
516 return isNonUnionUninit(R, {LocalChain, FR});
517
518 if (T->isUnionType()) {
519 if (isUnionUninit(R)) {
520 return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
521 } else {
522 IsAnyFieldInitialized = true;
523 return false;
524 }
525 }
526
527 if (T->isArrayType()) {
528 IsAnyFieldInitialized = true;
529 return false;
530 }
531
532 llvm_unreachable("All cases are handled!");
533 }
534
535 // TODO: If possible, it should be asserted that the DerefdV at this point is
536 // primitive.
537
538 if (isPrimitiveUninit(DerefdV))
539 return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
540
541 IsAnyFieldInitialized = true;
542 return false;
543}
544
545bool FindUninitializedFields::isMemberPointerUninit(const FieldRegion *FR,
546 FieldChainInfo LocalChain) {
547 assert(FR->getDecl()->getType()->isMemberPointerType() &&
548 "This function only checks regions that hold MemberPointerTypes!");
549 // TODO: Implement support for MemberPointerTypes.
550 return false;
551}
552
553bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
554 if (V.isUndef())
555 return true;
556
557 IsAnyFieldInitialized = true;
558 return false;
559}
560
561//===----------------------------------------------------------------------===//
562// Methods for FieldChainInfo.
563//===----------------------------------------------------------------------===//
564
565FieldChainInfo::FieldChainInfo(const FieldChainInfo &Other,
566 const FieldRegion *FR, const bool IsDereferenced)
567 : FieldChainInfo(Other, IsDereferenced) {
568 assert(!contains(FR) && "Can't add a field that is already a part of the "
569 "fieldchain! Is this a cyclic reference?");
570 Chain = Factory.add(FR, Other.Chain);
571}
572
573bool FieldChainInfo::isPointer() const {
574 assert(!Chain.isEmpty() && "Empty fieldchain!");
575 return (*Chain.begin())->getDecl()->getType()->isPointerType();
576}
577
578bool FieldChainInfo::isDereferenced() const {
579 assert(isPointer() && "Only pointers may or may not be dereferenced!");
580 return IsDereferenced;
581}
582
583const FieldDecl *FieldChainInfo::getEndOfChain() const {
584 assert(!Chain.isEmpty() && "Empty fieldchain!");
585 return (*Chain.begin())->getDecl();
586}
587
588// TODO: This function constructs an incorrect fieldchain string in the
589// following case:
590//
591// struct Base { int x; };
592// struct D1 : Base {}; struct D2 : Base {};
593//
594// struct MostDerived : D1, D2 {
595// MostDerived() {}
596// }
597//
598// A call to MostDerived::MostDerived() will cause two notes that say
599// "uninitialized field 'this->x'", but we can't refer to 'x' directly,
600// we need an explicit namespace resolution whether the uninit field was
601// 'D1::x' or 'D2::x'.
602//
603// TODO: If a field in the fieldchain is a captured lambda parameter, this
604// function constructs an empty string for it:
605//
606// template <class Callable> struct A {
607// Callable c;
608// A(const Callable &c, int) : c(c) {}
609// };
610//
611// int b; // say that this isn't zero initialized
612// auto alwaysTrue = [&b](int a) { return true; };
613//
614// A call with these parameters: A<decltype(alwaysTrue)>::A(alwaysTrue, int())
615// will emit a note with the message "uninitialized field: 'this->c.'". If
616// possible, the lambda parameter name should be retrieved or be replaced with a
617// "<lambda parameter>" or something similar.
618void FieldChainInfo::print(llvm::raw_ostream &Out) const {
619 if (Chain.isEmpty())
620 return;
621
622 const llvm::ImmutableListImpl<const FieldRegion *> *L =
623 Chain.getInternalPointer();
624 printTail(Out, L->getTail());
625 Out << L->getHead()->getDecl()->getNameAsString();
626}
627
628void FieldChainInfo::printTail(
629 llvm::raw_ostream &Out,
630 const llvm::ImmutableListImpl<const FieldRegion *> *L) {
631 if (!L)
632 return;
633
634 printTail(Out, L->getTail());
635 const FieldDecl *Field = L->getHead()->getDecl();
636 Out << Field->getNameAsString();
637 Out << (Field->getType()->isPointerType() ? "->" : ".");
638}
639
640//===----------------------------------------------------------------------===//
641// Utility functions.
642//===----------------------------------------------------------------------===//
643
Kristof Umanncc852442018-07-12 13:13:46 +0000644static bool isVoidPointer(const FieldDecl *FD) {
Kristof Umann30f08652018-06-18 11:50:17 +0000645 QualType T = FD->getType();
646
647 while (!T.isNull()) {
648 if (T->isVoidPointerType())
649 return true;
650 T = T->getPointeeType();
651 }
652 return false;
653}
654
Kristof Umanncc852442018-07-12 13:13:46 +0000655static Optional<nonloc::LazyCompoundVal>
Kristof Umann30f08652018-06-18 11:50:17 +0000656getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
657
658 Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
659 Context.getStackFrame());
660 // Getting the value for 'this'.
661 SVal This = Context.getState()->getSVal(ThisLoc);
662
663 // Getting the value for '*this'.
664 SVal Object = Context.getState()->getSVal(This.castAs<Loc>());
665
666 return Object.getAs<nonloc::LazyCompoundVal>();
667}
668
669// TODO: We should also check that if the constructor was called by another
670// constructor, whether those two are in any relation to one another. In it's
671// current state, this introduces some false negatives.
Kristof Umanncc852442018-07-12 13:13:46 +0000672static bool isCalledByConstructor(const CheckerContext &Context) {
Kristof Umann30f08652018-06-18 11:50:17 +0000673 const LocationContext *LC = Context.getLocationContext()->getParent();
674
675 while (LC) {
676 if (isa<CXXConstructorDecl>(LC->getDecl()))
677 return true;
678
679 LC = LC->getParent();
680 }
681 return false;
682}
683
Kristof Umanncc852442018-07-12 13:13:46 +0000684static void printNoteMessage(llvm::raw_ostream &Out,
685 const FieldChainInfo &Chain) {
Kristof Umann9bd44392018-06-29 11:25:24 +0000686 if (Chain.isPointer()) {
687 if (Chain.isDereferenced())
688 Out << "uninitialized pointee 'this->";
689 else
690 Out << "uninitialized pointer 'this->";
691 } else
692 Out << "uninitialized field 'this->";
693 Chain.print(Out);
694 Out << "'";
695}
696
Kristof Umann30f08652018-06-18 11:50:17 +0000697void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
698 auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
699 Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption(
700 "Pedantic", /*DefaultVal*/ false, Chk);
Kristof Umann9bd44392018-06-29 11:25:24 +0000701 Chk->ShouldConvertNotesToWarnings = Mgr.getAnalyzerOptions().getBooleanOption(
702 "NotesAsWarnings", /*DefaultVal*/ false, Chk);
Kristof Umann30f08652018-06-18 11:50:17 +0000703}