35 using namespace clang;
40 class UninitializedObjectChecker :
public Checker<check::EndFunction> {
41 std::unique_ptr<BuiltinBug> BT_uninitField;
46 bool ShouldConvertNotesToWarnings;
48 UninitializedObjectChecker()
49 : BT_uninitField(new
BuiltinBug(this,
"Uninitialized fields")) {}
60 class FieldChainInfo {
61 using FieldChain = llvm::ImmutableList<const FieldRegion *>;
65 const bool IsDereferenced =
false;
68 FieldChainInfo() =
default;
70 FieldChainInfo(
const FieldChainInfo &Other,
const bool IsDereferenced)
71 : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
73 FieldChainInfo(
const FieldChainInfo &Other,
const FieldRegion *FR,
74 const bool IsDereferenced =
false);
76 bool contains(
const FieldRegion *FR)
const {
return Chain.contains(FR); }
77 bool isPointer()
const;
82 bool isDereferenced()
const;
84 void print(llvm::raw_ostream &Out)
const;
91 static void printTail(llvm::raw_ostream &Out,
92 const llvm::ImmutableListImpl<const FieldRegion *> *L);
93 friend struct FieldChainInfoComparator;
96 struct FieldChainInfoComparator {
97 bool operator()(
const FieldChainInfo &lhs,
const FieldChainInfo &rhs)
const {
98 assert(!lhs.Chain.isEmpty() && !rhs.Chain.isEmpty() &&
99 "Attempted to store an empty fieldchain!");
100 return *lhs.Chain.begin() < *rhs.Chain.begin();
104 using UninitFieldSet = std::set<FieldChainInfo, FieldChainInfoComparator>;
107 class FindUninitializedFields {
111 const bool IsPedantic;
112 bool IsAnyFieldInitialized =
false;
114 UninitFieldSet UninitFields;
119 const UninitFieldSet &getUninitFields();
124 bool addFieldToUninits(FieldChainInfo LocalChain);
182 bool isNonUnionUninit(
const TypedValueRegion *R, FieldChainInfo LocalChain);
187 bool isPointerOrReferenceUninit(
const FieldRegion *FR,
188 FieldChainInfo LocalChain);
192 bool isPrimitiveUninit(
const SVal &V);
204 static llvm::ImmutableListFactory<const FieldRegion *>
Factory;
233 const FieldChainInfo &Chain);
243 void UninitializedObjectChecker::checkEndFunction(
246 const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
251 if (!CtorDecl->isUserProvided())
254 if (CtorDecl->getParent()->isUnion())
265 FindUninitializedFields F(Context.
getState(), Object->getRegion(),
268 const UninitFieldSet &UninitFields = F.getUninitFields();
270 if (UninitFields.empty())
287 if (ShouldConvertNotesToWarnings) {
288 for (
const auto &Chain : UninitFields) {
290 llvm::raw_svector_ostream WarningOS(WarningBuf);
294 auto Report = llvm::make_unique<BugReport>(
295 *BT_uninitField, WarningOS.str(),
Node, LocUsedForUniqueing,
303 llvm::raw_svector_ostream WarningOS(WarningBuf);
304 WarningOS << UninitFields.size() <<
" uninitialized field" 305 << (UninitFields.size() == 1 ?
"" :
"s")
306 <<
" at the end of the constructor call";
308 auto Report = llvm::make_unique<BugReport>(
309 *BT_uninitField, WarningOS.str(),
Node, LocUsedForUniqueing,
312 for (
const auto &Chain : UninitFields) {
314 llvm::raw_svector_ostream NoteOS(NoteBuf);
318 Report->addNote(NoteOS.str(),
329 FindUninitializedFields::FindUninitializedFields(
331 :
State(State), ObjectR(R), IsPedantic(IsPedantic) {}
333 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
334 isNonUnionUninit(ObjectR, FieldChainInfo());
336 if (!IsPedantic && !IsAnyFieldInitialized)
337 UninitFields.clear();
342 bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
343 if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
344 Chain.getEndOfChain()->getLocation()))
347 return UninitFields.insert(Chain).second;
351 FieldChainInfo LocalChain) {
354 "This method only checks non-union record objects!");
358 assert(RD &&
"Referred record has no definition");
360 bool ContainsUninitField =
false;
363 for (
const FieldDecl *I : RD->fields()) {
365 const auto FieldVal =
373 if (LocalChain.contains(FR))
376 if (T->isStructureOrClassType()) {
377 if (isNonUnionUninit(FR, {LocalChain, FR}))
378 ContainsUninitField =
true;
382 if (T->isUnionType()) {
383 if (isUnionUninit(FR)) {
384 if (addFieldToUninits({LocalChain, FR}))
385 ContainsUninitField =
true;
387 IsAnyFieldInitialized =
true;
391 if (T->isArrayType()) {
392 IsAnyFieldInitialized =
true;
396 if (T->isPointerType() || T->isReferenceType()) {
397 if (isPointerOrReferenceUninit(FR, LocalChain))
398 ContainsUninitField =
true;
403 SVal V = State->getSVal(FieldVal);
405 if (isPrimitiveUninit(V)) {
406 if (addFieldToUninits({LocalChain, FR}))
407 ContainsUninitField =
true;
412 llvm_unreachable(
"All cases are handled!");
430 return ContainsUninitField;
433 const auto *BaseRegion = State->getLValue(BaseSpec, R)
435 .getRegionAs<TypedValueRegion>();
437 if (isNonUnionUninit(BaseRegion, LocalChain))
438 ContainsUninitField =
true;
441 return ContainsUninitField;
446 "This method only checks union objects!");
453 bool FindUninitializedFields::isPointerOrReferenceUninit(
454 const FieldRegion *FR, FieldChainInfo LocalChain) {
458 "This method only checks pointer/reference objects!");
460 SVal V = State->getSVal(FR);
463 IsAnyFieldInitialized =
true;
468 return addFieldToUninits({LocalChain, FR});
476 IsAnyFieldInitialized =
true;
480 assert(V.
getAs<
Loc>() &&
"V should be Loc at this point!");
488 DerefdV = State->getSVal(*L);
503 IsAnyFieldInitialized =
true;
510 return isNonUnionUninit(R, {LocalChain, FR});
513 if (isUnionUninit(R)) {
514 return addFieldToUninits({LocalChain, FR,
true});
516 IsAnyFieldInitialized =
true;
522 IsAnyFieldInitialized =
true;
526 llvm_unreachable(
"All cases are handled!");
532 if (isPrimitiveUninit(DerefdV))
533 return addFieldToUninits({LocalChain, FR,
true});
535 IsAnyFieldInitialized =
true;
539 bool FindUninitializedFields::isPrimitiveUninit(
const SVal &V) {
543 IsAnyFieldInitialized =
true;
551 FieldChainInfo::FieldChainInfo(
const FieldChainInfo &Other,
553 : FieldChainInfo(Other, IsDereferenced) {
554 assert(!contains(FR) &&
"Can't add a field that is already a part of the " 555 "fieldchain! Is this a cyclic reference?");
556 Chain = Factory.add(FR, Other.Chain);
559 bool FieldChainInfo::isPointer()
const {
560 assert(!Chain.isEmpty() &&
"Empty fieldchain!");
561 return (*Chain.begin())->getDecl()->getType()->isPointerType();
564 bool FieldChainInfo::isDereferenced()
const {
565 assert(isPointer() &&
"Only pointers may or may not be dereferenced!");
566 return IsDereferenced;
569 const FieldDecl *FieldChainInfo::getEndOfChain()
const {
570 assert(!Chain.isEmpty() &&
"Empty fieldchain!");
571 return (*Chain.begin())->getDecl();
588 void FieldChainInfo::print(llvm::raw_ostream &Out)
const {
592 const llvm::ImmutableListImpl<const FieldRegion *> *L =
593 Chain.getInternalPointer();
594 printTail(Out, L->getTail());
598 void FieldChainInfo::printTail(
599 llvm::raw_ostream &Out,
600 const llvm::ImmutableListImpl<const FieldRegion *> *L) {
604 printTail(Out, L->getTail());
605 const FieldDecl *Field = L->getHead()->getDecl();
607 Out << (Field->getType()->isPointerType() ?
"->" :
".");
646 if (isa<CXXConstructorDecl>(LC->
getDecl()))
655 const FieldChainInfo &Chain) {
656 if (Chain.isPointer()) {
657 if (Chain.isDereferenced())
658 Out <<
"uninitialized pointee 'this->";
660 Out <<
"uninitialized pointer 'this->";
662 Out <<
"uninitialized field 'this->";
673 if (CXXParent && CXXParent->isLambda()) {
674 assert(CXXParent->captures_begin());
676 return It->getCapturedVar()->getName();
682 void ento::registerUninitializedObjectChecker(
CheckerManager &Mgr) {
685 "Pedantic",
false, Chk);
687 "NotesAsWarnings",
false, Chk);
TypedValueRegion - An abstract class representing regions having a typed value.
static StringRef getVariableName(const FieldDecl *Field)
Returns with Field's name.
A (possibly-)qualified type.
bool isMemberPointerType() const
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
const REGION * getRegionAs() const
bool isRecordType() const
virtual QualType getValueType() const =0
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined...
Represents a C++ constructor within a class.
bool isEnumeralType() const
const T * getAs() const
Member-template getAs<specific type>'.
loc::MemRegionVal getCXXThis(const CXXMethodDecl *D, const StackFrameContext *SFC)
Return a memory region for the 'this' object reference.
Represents a struct/union/class.
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
const FieldDecl * getDecl() const
Represents a member of a struct/union/class.
bool isReferenceType() const
static bool isCalledByConstructor(const CheckerContext &Context)
Checks whether the constructor under checking is called by another constructor.
const LocationContext * getLocationContext() const
const LocationContext * getParent() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
static Optional< nonloc::LazyCompoundVal > getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context)
Returns the object that was constructed by CtorDecl, or None if that isn't possible.
const Stmt * getCallSite() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
bool getBooleanOption(StringRef Name, bool DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option's string value as a boolean.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
CHECKER * registerChecker(AT... Args)
Used to register checkers.
bool isVoidPointerType() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
bool isStructureOrClassType() const
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static bool isVoidPointer(const FieldDecl *FD)
Returns whether FD can be (transitively) dereferenced to a void pointer type (void*, void**, ...).
bool isBuiltinType() const
Helper methods to distinguish type categories.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
ast_type_traits::DynTypedNode Node
static void printNoteMessage(llvm::raw_ostream &Out, const FieldChainInfo &Chain)
Constructs a note message for a given FieldChainInfo object.
Dataflow Directional Tag Classes.
bool isZeroConstant() const
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
static bool isPrimitiveType(const QualType &T)
Returns true if T is a primitive type.
AnalyzerOptions & getAnalyzerOptions()
const Decl * getDecl() const
const StackFrameContext * getStackFrame() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
const ProgramStateRef & getState() const
Represents a base class of a C++ class.
Represents a C++ struct/union/class.
SourceManager & getSourceManager()
SValBuilder & getSValBuilder()
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
bool isPointerType() const
static llvm::ImmutableListFactory< const FieldRegion * > Factory
capture_const_iterator captures_begin() const
const LocationContext * getLocationContext() const