156963aecSKristof Umann //===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==//
256963aecSKristof Umann //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
656963aecSKristof Umann //
756963aecSKristof Umann //===----------------------------------------------------------------------===//
856963aecSKristof Umann //
956963aecSKristof Umann // This file defines a checker that reports uninitialized fields in objects
1056963aecSKristof Umann // created after a constructor call.
1156963aecSKristof Umann //
126cec6c46SKristof Umann // To read about command line options and how the checker works, refer to the
136cec6c46SKristof Umann // top of the file and inline comments in UninitializedObject.h.
1456963aecSKristof Umann //
1556963aecSKristof Umann // Some of the logic is implemented in UninitializedPointee.cpp, to reduce the
1656963aecSKristof Umann // complexity of this file.
1756963aecSKristof Umann //
1856963aecSKristof Umann //===----------------------------------------------------------------------===//
1956963aecSKristof Umann
2076a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21a37bba47SKristof Umann #include "UninitializedObject.h"
22ffe93a16SKristof Umann #include "clang/ASTMatchers/ASTMatchFinder.h"
23748c139aSKristof Umann #include "clang/Driver/DriverDiagnostic.h"
2456963aecSKristof Umann #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2556963aecSKristof Umann #include "clang/StaticAnalyzer/Core/Checker.h"
2656963aecSKristof Umann #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
27e4bf456fSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
2856963aecSKristof Umann
2956963aecSKristof Umann using namespace clang;
3056963aecSKristof Umann using namespace clang::ento;
31ffe93a16SKristof Umann using namespace clang::ast_matchers;
3256963aecSKristof Umann
334ff77699SKristof Umann /// We'll mark fields (and pointee of fields) that are confirmed to be
344ff77699SKristof Umann /// uninitialized as already analyzed.
354ff77699SKristof Umann REGISTER_SET_WITH_PROGRAMSTATE(AnalyzedRegions, const MemRegion *)
364ff77699SKristof Umann
3756963aecSKristof Umann namespace {
3856963aecSKristof Umann
394ff77699SKristof Umann class UninitializedObjectChecker
404ff77699SKristof Umann : public Checker<check::EndFunction, check::DeadSymbols> {
4156963aecSKristof Umann std::unique_ptr<BuiltinBug> BT_uninitField;
4256963aecSKristof Umann
4356963aecSKristof Umann public:
446cec6c46SKristof Umann // The fields of this struct will be initialized when registering the checker.
456cec6c46SKristof Umann UninitObjCheckerOptions Opts;
4656963aecSKristof Umann
UninitializedObjectChecker()4756963aecSKristof Umann UninitializedObjectChecker()
4856963aecSKristof Umann : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
494ff77699SKristof Umann
5056963aecSKristof Umann void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
514ff77699SKristof Umann void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
5256963aecSKristof Umann };
5356963aecSKristof Umann
54015b0595SKristof Umann /// A basic field type, that is not a pointer or a reference, it's dynamic and
55015b0595SKristof Umann /// static type is the same.
56651d683eSRichard Smith class RegularField final : public FieldNode {
57015b0595SKristof Umann public:
RegularField(const FieldRegion * FR)58015b0595SKristof Umann RegularField(const FieldRegion *FR) : FieldNode(FR) {}
59015b0595SKristof Umann
printNoteMsg(llvm::raw_ostream & Out) const60*a210f404SKazu Hirata void printNoteMsg(llvm::raw_ostream &Out) const override {
61015b0595SKristof Umann Out << "uninitialized field ";
62015b0595SKristof Umann }
63015b0595SKristof Umann
printPrefix(llvm::raw_ostream & Out) const64*a210f404SKazu Hirata void printPrefix(llvm::raw_ostream &Out) const override {}
65015b0595SKristof Umann
printNode(llvm::raw_ostream & Out) const66*a210f404SKazu Hirata void printNode(llvm::raw_ostream &Out) const override {
67015b0595SKristof Umann Out << getVariableName(getDecl());
68015b0595SKristof Umann }
69015b0595SKristof Umann
printSeparator(llvm::raw_ostream & Out) const70*a210f404SKazu Hirata void printSeparator(llvm::raw_ostream &Out) const override { Out << '.'; }
71015b0595SKristof Umann };
72015b0595SKristof Umann
73b59b45e7SKristof Umann /// Represents that the FieldNode that comes after this is declared in a base
74ceb5f654SKristof Umann /// of the previous FieldNode. As such, this descendant doesn't wrap a
75ceb5f654SKristof Umann /// FieldRegion, and is purely a tool to describe a relation between two other
76ceb5f654SKristof Umann /// FieldRegion wrapping descendants.
77b59b45e7SKristof Umann class BaseClass final : public FieldNode {
78b59b45e7SKristof Umann const QualType BaseClassT;
79b59b45e7SKristof Umann
80b59b45e7SKristof Umann public:
BaseClass(const QualType & T)81b59b45e7SKristof Umann BaseClass(const QualType &T) : FieldNode(nullptr), BaseClassT(T) {
82b59b45e7SKristof Umann assert(!T.isNull());
83b59b45e7SKristof Umann assert(T->getAsCXXRecordDecl());
84b59b45e7SKristof Umann }
85b59b45e7SKristof Umann
printNoteMsg(llvm::raw_ostream & Out) const86*a210f404SKazu Hirata void printNoteMsg(llvm::raw_ostream &Out) const override {
87b59b45e7SKristof Umann llvm_unreachable("This node can never be the final node in the "
88b59b45e7SKristof Umann "fieldchain!");
89b59b45e7SKristof Umann }
90b59b45e7SKristof Umann
printPrefix(llvm::raw_ostream & Out) const91*a210f404SKazu Hirata void printPrefix(llvm::raw_ostream &Out) const override {}
92b59b45e7SKristof Umann
printNode(llvm::raw_ostream & Out) const93*a210f404SKazu Hirata void printNode(llvm::raw_ostream &Out) const override {
94b59b45e7SKristof Umann Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
95b59b45e7SKristof Umann }
96b59b45e7SKristof Umann
printSeparator(llvm::raw_ostream & Out) const97*a210f404SKazu Hirata void printSeparator(llvm::raw_ostream &Out) const override {}
98b59b45e7SKristof Umann
isBase() const99*a210f404SKazu Hirata bool isBase() const override { return true; }
100b59b45e7SKristof Umann };
101b59b45e7SKristof Umann
10256963aecSKristof Umann } // end of anonymous namespace
10356963aecSKristof Umann
10456963aecSKristof Umann // Utility function declarations.
10556963aecSKristof Umann
106dbabdfacSKristof Umann /// Returns the region that was constructed by CtorDecl, or nullptr if that
107dbabdfacSKristof Umann /// isn't possible.
108dbabdfacSKristof Umann static const TypedValueRegion *
109dbabdfacSKristof Umann getConstructedRegion(const CXXConstructorDecl *CtorDecl,
110dbabdfacSKristof Umann CheckerContext &Context);
11156963aecSKristof Umann
11256963aecSKristof Umann /// Checks whether the object constructed by \p Ctor will be analyzed later
11356963aecSKristof Umann /// (e.g. if the object is a field of another object, in which case we'd check
11456963aecSKristof Umann /// it multiple times).
11556963aecSKristof Umann static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
11656963aecSKristof Umann CheckerContext &Context);
11756963aecSKristof Umann
118d6145d98SKristof Umann /// Checks whether RD contains a field with a name or type name that matches
119d6145d98SKristof Umann /// \p Pattern.
120d6145d98SKristof Umann static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern);
121d6145d98SKristof Umann
122ffe93a16SKristof Umann /// Checks _syntactically_ whether it is possible to access FD from the record
123ffe93a16SKristof Umann /// that contains it without a preceding assert (even if that access happens
124ffe93a16SKristof Umann /// inside a method). This is mainly used for records that act like unions, like
125ffe93a16SKristof Umann /// having multiple bit fields, with only a fraction being properly initialized.
126ffe93a16SKristof Umann /// If these fields are properly guarded with asserts, this method returns
127ffe93a16SKristof Umann /// false.
128ffe93a16SKristof Umann ///
129ffe93a16SKristof Umann /// Since this check is done syntactically, this method could be inaccurate.
130ffe93a16SKristof Umann static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State);
131ffe93a16SKristof Umann
13256963aecSKristof Umann //===----------------------------------------------------------------------===//
13356963aecSKristof Umann // Methods for UninitializedObjectChecker.
13456963aecSKristof Umann //===----------------------------------------------------------------------===//
13556963aecSKristof Umann
checkEndFunction(const ReturnStmt * RS,CheckerContext & Context) const13656963aecSKristof Umann void UninitializedObjectChecker::checkEndFunction(
13756963aecSKristof Umann const ReturnStmt *RS, CheckerContext &Context) const {
13856963aecSKristof Umann
13956963aecSKristof Umann const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
14056963aecSKristof Umann Context.getLocationContext()->getDecl());
14156963aecSKristof Umann if (!CtorDecl)
14256963aecSKristof Umann return;
14356963aecSKristof Umann
14456963aecSKristof Umann if (!CtorDecl->isUserProvided())
14556963aecSKristof Umann return;
14656963aecSKristof Umann
14756963aecSKristof Umann if (CtorDecl->getParent()->isUnion())
14856963aecSKristof Umann return;
14956963aecSKristof Umann
15056963aecSKristof Umann // This avoids essentially the same error being reported multiple times.
15156963aecSKristof Umann if (willObjectBeAnalyzedLater(CtorDecl, Context))
15256963aecSKristof Umann return;
15356963aecSKristof Umann
154dbabdfacSKristof Umann const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
155dbabdfacSKristof Umann if (!R)
15656963aecSKristof Umann return;
15756963aecSKristof Umann
158dbabdfacSKristof Umann FindUninitializedFields F(Context.getState(), R, Opts);
15956963aecSKristof Umann
1604ff77699SKristof Umann std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
1614ff77699SKristof Umann F.getResults();
16256963aecSKristof Umann
1634ff77699SKristof Umann ProgramStateRef UpdatedState = UninitInfo.first;
1644ff77699SKristof Umann const UninitFieldMap &UninitFields = UninitInfo.second;
1654ff77699SKristof Umann
1664ff77699SKristof Umann if (UninitFields.empty()) {
1674ff77699SKristof Umann Context.addTransition(UpdatedState);
16856963aecSKristof Umann return;
1694ff77699SKristof Umann }
17056963aecSKristof Umann
17156963aecSKristof Umann // There are uninitialized fields in the record.
17256963aecSKristof Umann
1734ff77699SKristof Umann ExplodedNode *Node = Context.generateNonFatalErrorNode(UpdatedState);
17456963aecSKristof Umann if (!Node)
17556963aecSKristof Umann return;
17656963aecSKristof Umann
17756963aecSKristof Umann PathDiagnosticLocation LocUsedForUniqueing;
17856963aecSKristof Umann const Stmt *CallSite = Context.getStackFrame()->getCallSite();
17956963aecSKristof Umann if (CallSite)
18056963aecSKristof Umann LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
18156963aecSKristof Umann CallSite, Context.getSourceManager(), Node->getLocationContext());
18256963aecSKristof Umann
18356963aecSKristof Umann // For Plist consumers that don't support notes just yet, we'll convert notes
18456963aecSKristof Umann // to warnings.
1856cec6c46SKristof Umann if (Opts.ShouldConvertNotesToWarnings) {
186015b0595SKristof Umann for (const auto &Pair : UninitFields) {
18756963aecSKristof Umann
1882f169e7cSArtem Dergachev auto Report = std::make_unique<PathSensitiveBugReport>(
189015b0595SKristof Umann *BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
19056963aecSKristof Umann Node->getLocationContext()->getDecl());
19156963aecSKristof Umann Context.emitReport(std::move(Report));
19256963aecSKristof Umann }
19356963aecSKristof Umann return;
19456963aecSKristof Umann }
19556963aecSKristof Umann
19656963aecSKristof Umann SmallString<100> WarningBuf;
19756963aecSKristof Umann llvm::raw_svector_ostream WarningOS(WarningBuf);
19856963aecSKristof Umann WarningOS << UninitFields.size() << " uninitialized field"
19956963aecSKristof Umann << (UninitFields.size() == 1 ? "" : "s")
20056963aecSKristof Umann << " at the end of the constructor call";
20156963aecSKristof Umann
2022f169e7cSArtem Dergachev auto Report = std::make_unique<PathSensitiveBugReport>(
20356963aecSKristof Umann *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
20456963aecSKristof Umann Node->getLocationContext()->getDecl());
20556963aecSKristof Umann
206015b0595SKristof Umann for (const auto &Pair : UninitFields) {
207015b0595SKristof Umann Report->addNote(Pair.second,
208015b0595SKristof Umann PathDiagnosticLocation::create(Pair.first->getDecl(),
20956963aecSKristof Umann Context.getSourceManager()));
21056963aecSKristof Umann }
21156963aecSKristof Umann Context.emitReport(std::move(Report));
21256963aecSKristof Umann }
21356963aecSKristof Umann
checkDeadSymbols(SymbolReaper & SR,CheckerContext & C) const2144ff77699SKristof Umann void UninitializedObjectChecker::checkDeadSymbols(SymbolReaper &SR,
2154ff77699SKristof Umann CheckerContext &C) const {
2164ff77699SKristof Umann ProgramStateRef State = C.getState();
2174ff77699SKristof Umann for (const MemRegion *R : State->get<AnalyzedRegions>()) {
2184ff77699SKristof Umann if (!SR.isLiveRegion(R))
2194ff77699SKristof Umann State = State->remove<AnalyzedRegions>(R);
2204ff77699SKristof Umann }
2214ff77699SKristof Umann }
2224ff77699SKristof Umann
22356963aecSKristof Umann //===----------------------------------------------------------------------===//
22456963aecSKristof Umann // Methods for FindUninitializedFields.
22556963aecSKristof Umann //===----------------------------------------------------------------------===//
22656963aecSKristof Umann
FindUninitializedFields(ProgramStateRef State,const TypedValueRegion * const R,const UninitObjCheckerOptions & Opts)22756963aecSKristof Umann FindUninitializedFields::FindUninitializedFields(
22823ca9660SKristof Umann ProgramStateRef State, const TypedValueRegion *const R,
2296cec6c46SKristof Umann const UninitObjCheckerOptions &Opts)
2306cec6c46SKristof Umann : State(State), ObjectR(R), Opts(Opts) {
23156963aecSKristof Umann
232015b0595SKristof Umann isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
2336cec6c46SKristof Umann
2346cec6c46SKristof Umann // In non-pedantic mode, if ObjectR doesn't contain a single initialized
2356cec6c46SKristof Umann // field, we'll assume that Object was intentionally left uninitialized.
2366cec6c46SKristof Umann if (!Opts.IsPedantic && !isAnyFieldInitialized())
2376cec6c46SKristof Umann UninitFields.clear();
23856963aecSKristof Umann }
23956963aecSKristof Umann
addFieldToUninits(FieldChainInfo Chain,const MemRegion * PointeeR)2404ff77699SKristof Umann bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain,
2414ff77699SKristof Umann const MemRegion *PointeeR) {
2424ff77699SKristof Umann const FieldRegion *FR = Chain.getUninitRegion();
2434ff77699SKristof Umann
2444ff77699SKristof Umann assert((PointeeR || !isDereferencableType(FR->getDecl()->getType())) &&
2454ff77699SKristof Umann "One must also pass the pointee region as a parameter for "
246b23ccecbSRaphael Isemann "dereferenceable fields!");
2474ff77699SKristof Umann
248ffe93a16SKristof Umann if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
249ffe93a16SKristof Umann FR->getDecl()->getLocation()))
250ffe93a16SKristof Umann return false;
251ffe93a16SKristof Umann
252ffe93a16SKristof Umann if (Opts.IgnoreGuardedFields && !hasUnguardedAccess(FR->getDecl(), State))
253ffe93a16SKristof Umann return false;
254ffe93a16SKristof Umann
2554ff77699SKristof Umann if (State->contains<AnalyzedRegions>(FR))
2564ff77699SKristof Umann return false;
2574ff77699SKristof Umann
2584ff77699SKristof Umann if (PointeeR) {
2594ff77699SKristof Umann if (State->contains<AnalyzedRegions>(PointeeR)) {
2604ff77699SKristof Umann return false;
2614ff77699SKristof Umann }
2624ff77699SKristof Umann State = State->add<AnalyzedRegions>(PointeeR);
2634ff77699SKristof Umann }
2644ff77699SKristof Umann
2654ff77699SKristof Umann State = State->add<AnalyzedRegions>(FR);
2664ff77699SKristof Umann
267015b0595SKristof Umann UninitFieldMap::mapped_type NoteMsgBuf;
268015b0595SKristof Umann llvm::raw_svector_ostream OS(NoteMsgBuf);
269015b0595SKristof Umann Chain.printNoteMsg(OS);
270ffe93a16SKristof Umann
2714ff77699SKristof Umann return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;
27256963aecSKristof Umann }
27356963aecSKristof Umann
isNonUnionUninit(const TypedValueRegion * R,FieldChainInfo LocalChain)27456963aecSKristof Umann bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
27556963aecSKristof Umann FieldChainInfo LocalChain) {
27656963aecSKristof Umann assert(R->getValueType()->isRecordType() &&
27756963aecSKristof Umann !R->getValueType()->isUnionType() &&
27856963aecSKristof Umann "This method only checks non-union record objects!");
27956963aecSKristof Umann
280f0dd1016SKristof Umann const RecordDecl *RD = R->getValueType()->getAsRecordDecl()->getDefinition();
281f0dd1016SKristof Umann
282f0dd1016SKristof Umann if (!RD) {
283f0dd1016SKristof Umann IsAnyFieldInitialized = true;
284f0dd1016SKristof Umann return true;
285f0dd1016SKristof Umann }
28656963aecSKristof Umann
287d6145d98SKristof Umann if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
288d6145d98SKristof Umann shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
289d6145d98SKristof Umann IsAnyFieldInitialized = true;
290d6145d98SKristof Umann return false;
291d6145d98SKristof Umann }
292d6145d98SKristof Umann
29356963aecSKristof Umann bool ContainsUninitField = false;
29456963aecSKristof Umann
29556963aecSKristof Umann // Are all of this non-union's fields initialized?
29656963aecSKristof Umann for (const FieldDecl *I : RD->fields()) {
29756963aecSKristof Umann
29856963aecSKristof Umann const auto FieldVal =
29956963aecSKristof Umann State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
30056963aecSKristof Umann const auto *FR = FieldVal.getRegionAs<FieldRegion>();
30156963aecSKristof Umann QualType T = I->getType();
30256963aecSKristof Umann
30356963aecSKristof Umann // If LocalChain already contains FR, then we encountered a cyclic
30456963aecSKristof Umann // reference. In this case, region FR is already under checking at an
30556963aecSKristof Umann // earlier node in the directed tree.
30656963aecSKristof Umann if (LocalChain.contains(FR))
30756963aecSKristof Umann return false;
30856963aecSKristof Umann
30956963aecSKristof Umann if (T->isStructureOrClassType()) {
310015b0595SKristof Umann if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))
31156963aecSKristof Umann ContainsUninitField = true;
31256963aecSKristof Umann continue;
31356963aecSKristof Umann }
31456963aecSKristof Umann
31556963aecSKristof Umann if (T->isUnionType()) {
31656963aecSKristof Umann if (isUnionUninit(FR)) {
317015b0595SKristof Umann if (addFieldToUninits(LocalChain.add(RegularField(FR))))
31856963aecSKristof Umann ContainsUninitField = true;
31956963aecSKristof Umann } else
32056963aecSKristof Umann IsAnyFieldInitialized = true;
32156963aecSKristof Umann continue;
32256963aecSKristof Umann }
32356963aecSKristof Umann
32456963aecSKristof Umann if (T->isArrayType()) {
32556963aecSKristof Umann IsAnyFieldInitialized = true;
32656963aecSKristof Umann continue;
32756963aecSKristof Umann }
32856963aecSKristof Umann
329f051379fSKristof Umann SVal V = State->getSVal(FieldVal);
330f051379fSKristof Umann
33196ccb690SBalazs Benics if (isDereferencableType(T) || isa<nonloc::LocAsInteger>(V)) {
332ceb5f654SKristof Umann if (isDereferencableUninit(FR, LocalChain))
33356963aecSKristof Umann ContainsUninitField = true;
33456963aecSKristof Umann continue;
33556963aecSKristof Umann }
33656963aecSKristof Umann
33756963aecSKristof Umann if (isPrimitiveType(T)) {
33856963aecSKristof Umann if (isPrimitiveUninit(V)) {
339015b0595SKristof Umann if (addFieldToUninits(LocalChain.add(RegularField(FR))))
34056963aecSKristof Umann ContainsUninitField = true;
34156963aecSKristof Umann }
34256963aecSKristof Umann continue;
34356963aecSKristof Umann }
34456963aecSKristof Umann
34556963aecSKristof Umann llvm_unreachable("All cases are handled!");
34656963aecSKristof Umann }
34756963aecSKristof Umann
348ceb5f654SKristof Umann // Checking bases. The checker will regard inherited data members as direct
349ceb5f654SKristof Umann // fields.
35056963aecSKristof Umann const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
35156963aecSKristof Umann if (!CXXRD)
35256963aecSKristof Umann return ContainsUninitField;
35356963aecSKristof Umann
35456963aecSKristof Umann for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
35556963aecSKristof Umann const auto *BaseRegion = State->getLValue(BaseSpec, R)
35656963aecSKristof Umann .castAs<loc::MemRegionVal>()
35756963aecSKristof Umann .getRegionAs<TypedValueRegion>();
35856963aecSKristof Umann
359b59b45e7SKristof Umann // If the head of the list is also a BaseClass, we'll overwrite it to avoid
360b59b45e7SKristof Umann // note messages like 'this->A::B::x'.
361b59b45e7SKristof Umann if (!LocalChain.isEmpty() && LocalChain.getHead().isBase()) {
362b59b45e7SKristof Umann if (isNonUnionUninit(BaseRegion, LocalChain.replaceHead(
363b59b45e7SKristof Umann BaseClass(BaseSpec.getType()))))
36456963aecSKristof Umann ContainsUninitField = true;
365b59b45e7SKristof Umann } else {
366b59b45e7SKristof Umann if (isNonUnionUninit(BaseRegion,
367b59b45e7SKristof Umann LocalChain.add(BaseClass(BaseSpec.getType()))))
368b59b45e7SKristof Umann ContainsUninitField = true;
369b59b45e7SKristof Umann }
37056963aecSKristof Umann }
37156963aecSKristof Umann
37256963aecSKristof Umann return ContainsUninitField;
37356963aecSKristof Umann }
37456963aecSKristof Umann
isUnionUninit(const TypedValueRegion * R)37556963aecSKristof Umann bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
37656963aecSKristof Umann assert(R->getValueType()->isUnionType() &&
37756963aecSKristof Umann "This method only checks union objects!");
37856963aecSKristof Umann // TODO: Implement support for union fields.
37956963aecSKristof Umann return false;
38056963aecSKristof Umann }
38156963aecSKristof Umann
isPrimitiveUninit(const SVal & V)38256963aecSKristof Umann bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
38356963aecSKristof Umann if (V.isUndef())
38456963aecSKristof Umann return true;
38556963aecSKristof Umann
38656963aecSKristof Umann IsAnyFieldInitialized = true;
38756963aecSKristof Umann return false;
38856963aecSKristof Umann }
38956963aecSKristof Umann
39056963aecSKristof Umann //===----------------------------------------------------------------------===//
39156963aecSKristof Umann // Methods for FieldChainInfo.
39256963aecSKristof Umann //===----------------------------------------------------------------------===//
39356963aecSKristof Umann
contains(const FieldRegion * FR) const394015b0595SKristof Umann bool FieldChainInfo::contains(const FieldRegion *FR) const {
395015b0595SKristof Umann for (const FieldNode &Node : Chain) {
396015b0595SKristof Umann if (Node.isSameRegion(FR))
397015b0595SKristof Umann return true;
39856963aecSKristof Umann }
399015b0595SKristof Umann return false;
40056963aecSKristof Umann }
40156963aecSKristof Umann
402a37bba47SKristof Umann /// Prints every element except the last to `Out`. Since ImmutableLists store
403a37bba47SKristof Umann /// elements in reverse order, and have no reverse iterators, we use a
404a37bba47SKristof Umann /// recursive function to print the fieldchain correctly. The last element in
405ceb5f654SKristof Umann /// the chain is to be printed by `FieldChainInfo::print`.
406a37bba47SKristof Umann static void printTail(llvm::raw_ostream &Out,
40782eeca36SKristof Umann const FieldChainInfo::FieldChain L);
408a37bba47SKristof Umann
409ceb5f654SKristof Umann // FIXME: This function constructs an incorrect string in the following case:
41056963aecSKristof Umann //
41156963aecSKristof Umann // struct Base { int x; };
41256963aecSKristof Umann // struct D1 : Base {}; struct D2 : Base {};
41356963aecSKristof Umann //
41456963aecSKristof Umann // struct MostDerived : D1, D2 {
41556963aecSKristof Umann // MostDerived() {}
41656963aecSKristof Umann // }
41756963aecSKristof Umann //
41856963aecSKristof Umann // A call to MostDerived::MostDerived() will cause two notes that say
41956963aecSKristof Umann // "uninitialized field 'this->x'", but we can't refer to 'x' directly,
42056963aecSKristof Umann // we need an explicit namespace resolution whether the uninit field was
42156963aecSKristof Umann // 'D1::x' or 'D2::x'.
printNoteMsg(llvm::raw_ostream & Out) const422015b0595SKristof Umann void FieldChainInfo::printNoteMsg(llvm::raw_ostream &Out) const {
42356963aecSKristof Umann if (Chain.isEmpty())
42456963aecSKristof Umann return;
42556963aecSKristof Umann
42682eeca36SKristof Umann const FieldNode &LastField = getHead();
427015b0595SKristof Umann
428015b0595SKristof Umann LastField.printNoteMsg(Out);
429015b0595SKristof Umann Out << '\'';
430015b0595SKristof Umann
431015b0595SKristof Umann for (const FieldNode &Node : Chain)
432015b0595SKristof Umann Node.printPrefix(Out);
433015b0595SKristof Umann
434015b0595SKristof Umann Out << "this->";
43582eeca36SKristof Umann printTail(Out, Chain.getTail());
436015b0595SKristof Umann LastField.printNode(Out);
437015b0595SKristof Umann Out << '\'';
43856963aecSKristof Umann }
43956963aecSKristof Umann
printTail(llvm::raw_ostream & Out,const FieldChainInfo::FieldChain L)440a37bba47SKristof Umann static void printTail(llvm::raw_ostream &Out,
44182eeca36SKristof Umann const FieldChainInfo::FieldChain L) {
44282eeca36SKristof Umann if (L.isEmpty())
44356963aecSKristof Umann return;
44456963aecSKristof Umann
44582eeca36SKristof Umann printTail(Out, L.getTail());
446015b0595SKristof Umann
44782eeca36SKristof Umann L.getHead().printNode(Out);
44882eeca36SKristof Umann L.getHead().printSeparator(Out);
44956963aecSKristof Umann }
45056963aecSKristof Umann
45156963aecSKristof Umann //===----------------------------------------------------------------------===//
45256963aecSKristof Umann // Utility functions.
45356963aecSKristof Umann //===----------------------------------------------------------------------===//
45456963aecSKristof Umann
455dbabdfacSKristof Umann static const TypedValueRegion *
getConstructedRegion(const CXXConstructorDecl * CtorDecl,CheckerContext & Context)456dbabdfacSKristof Umann getConstructedRegion(const CXXConstructorDecl *CtorDecl,
457dbabdfacSKristof Umann CheckerContext &Context) {
45856963aecSKristof Umann
459ffe93a16SKristof Umann Loc ThisLoc =
460ffe93a16SKristof Umann Context.getSValBuilder().getCXXThis(CtorDecl, Context.getStackFrame());
46156963aecSKristof Umann
462dbabdfacSKristof Umann SVal ObjectV = Context.getState()->getSVal(ThisLoc);
46356963aecSKristof Umann
464dbabdfacSKristof Umann auto *R = ObjectV.getAsRegion()->getAs<TypedValueRegion>();
465dbabdfacSKristof Umann if (R && !R->getValueType()->getAsCXXRecordDecl())
466dbabdfacSKristof Umann return nullptr;
467dbabdfacSKristof Umann
468dbabdfacSKristof Umann return R;
46956963aecSKristof Umann }
47056963aecSKristof Umann
willObjectBeAnalyzedLater(const CXXConstructorDecl * Ctor,CheckerContext & Context)47156963aecSKristof Umann static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
47256963aecSKristof Umann CheckerContext &Context) {
47356963aecSKristof Umann
474dbabdfacSKristof Umann const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
475dbabdfacSKristof Umann if (!CurrRegion)
47656963aecSKristof Umann return false;
47756963aecSKristof Umann
47856963aecSKristof Umann const LocationContext *LC = Context.getLocationContext();
47956963aecSKristof Umann while ((LC = LC->getParent())) {
48056963aecSKristof Umann
48156963aecSKristof Umann // If \p Ctor was called by another constructor.
48256963aecSKristof Umann const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(LC->getDecl());
48356963aecSKristof Umann if (!OtherCtor)
48456963aecSKristof Umann continue;
48556963aecSKristof Umann
486dbabdfacSKristof Umann const TypedValueRegion *OtherRegion =
487dbabdfacSKristof Umann getConstructedRegion(OtherCtor, Context);
488dbabdfacSKristof Umann if (!OtherRegion)
48956963aecSKristof Umann continue;
49056963aecSKristof Umann
491dbabdfacSKristof Umann // If the CurrRegion is a subregion of OtherRegion, it will be analyzed
492dbabdfacSKristof Umann // during the analysis of OtherRegion.
493dbabdfacSKristof Umann if (CurrRegion->isSubRegionOf(OtherRegion))
49456963aecSKristof Umann return true;
49556963aecSKristof Umann }
49656963aecSKristof Umann
49756963aecSKristof Umann return false;
49856963aecSKristof Umann }
49956963aecSKristof Umann
shouldIgnoreRecord(const RecordDecl * RD,StringRef Pattern)500d6145d98SKristof Umann static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
501d6145d98SKristof Umann llvm::Regex R(Pattern);
502d6145d98SKristof Umann
503d6145d98SKristof Umann for (const FieldDecl *FD : RD->fields()) {
504d6145d98SKristof Umann if (R.match(FD->getType().getAsString()))
505d6145d98SKristof Umann return true;
506d6145d98SKristof Umann if (R.match(FD->getName()))
507d6145d98SKristof Umann return true;
508d6145d98SKristof Umann }
509d6145d98SKristof Umann
510d6145d98SKristof Umann return false;
511d6145d98SKristof Umann }
512d6145d98SKristof Umann
getMethodBody(const CXXMethodDecl * M)513ffe93a16SKristof Umann static const Stmt *getMethodBody(const CXXMethodDecl *M) {
514ffe93a16SKristof Umann if (isa<CXXConstructorDecl>(M))
515ffe93a16SKristof Umann return nullptr;
516ffe93a16SKristof Umann
517ffe93a16SKristof Umann if (!M->isDefined())
518ffe93a16SKristof Umann return nullptr;
519ffe93a16SKristof Umann
520ffe93a16SKristof Umann return M->getDefinition()->getBody();
521ffe93a16SKristof Umann }
522ffe93a16SKristof Umann
hasUnguardedAccess(const FieldDecl * FD,ProgramStateRef State)523ffe93a16SKristof Umann static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State) {
524ffe93a16SKristof Umann
525ffe93a16SKristof Umann if (FD->getAccess() == AccessSpecifier::AS_public)
526ffe93a16SKristof Umann return true;
527ffe93a16SKristof Umann
528ffe93a16SKristof Umann const auto *Parent = dyn_cast<CXXRecordDecl>(FD->getParent());
529ffe93a16SKristof Umann
530ffe93a16SKristof Umann if (!Parent)
531ffe93a16SKristof Umann return true;
532ffe93a16SKristof Umann
533ffe93a16SKristof Umann Parent = Parent->getDefinition();
534ffe93a16SKristof Umann assert(Parent && "The record's definition must be avaible if an uninitialized"
535ffe93a16SKristof Umann " field of it was found!");
536ffe93a16SKristof Umann
537ffe93a16SKristof Umann ASTContext &AC = State->getStateManager().getContext();
538ffe93a16SKristof Umann
539ffe93a16SKristof Umann auto FieldAccessM = memberExpr(hasDeclaration(equalsNode(FD))).bind("access");
540ffe93a16SKristof Umann
541ffe93a16SKristof Umann auto AssertLikeM = callExpr(callee(functionDecl(
54241bbb875SNathan James hasAnyName("exit", "panic", "error", "Assert", "assert", "ziperr",
54341bbb875SNathan James "assfail", "db_error", "__assert", "__assert2", "_wassert",
54441bbb875SNathan James "__assert_rtn", "__assert_fail", "dtrace_assfail",
54541bbb875SNathan James "yy_fatal_error", "_XCAssertionFailureHandler",
54641bbb875SNathan James "_DTAssertionFailureHandler", "_TSAssertionFailureHandler"))));
547ffe93a16SKristof Umann
548ffe93a16SKristof Umann auto NoReturnFuncM = callExpr(callee(functionDecl(isNoReturn())));
549ffe93a16SKristof Umann
550ffe93a16SKristof Umann auto GuardM =
551ffe93a16SKristof Umann stmt(anyOf(ifStmt(), switchStmt(), conditionalOperator(), AssertLikeM,
552ffe93a16SKristof Umann NoReturnFuncM))
553ffe93a16SKristof Umann .bind("guard");
554ffe93a16SKristof Umann
555ffe93a16SKristof Umann for (const CXXMethodDecl *M : Parent->methods()) {
556ffe93a16SKristof Umann const Stmt *MethodBody = getMethodBody(M);
557ffe93a16SKristof Umann if (!MethodBody)
558ffe93a16SKristof Umann continue;
559ffe93a16SKristof Umann
560ffe93a16SKristof Umann auto Accesses = match(stmt(hasDescendant(FieldAccessM)), *MethodBody, AC);
561ffe93a16SKristof Umann if (Accesses.empty())
562ffe93a16SKristof Umann continue;
563ffe93a16SKristof Umann const auto *FirstAccess = Accesses[0].getNodeAs<MemberExpr>("access");
564ffe93a16SKristof Umann assert(FirstAccess);
565ffe93a16SKristof Umann
566ffe93a16SKristof Umann auto Guards = match(stmt(hasDescendant(GuardM)), *MethodBody, AC);
567ffe93a16SKristof Umann if (Guards.empty())
568ffe93a16SKristof Umann return true;
569ffe93a16SKristof Umann const auto *FirstGuard = Guards[0].getNodeAs<Stmt>("guard");
570ffe93a16SKristof Umann assert(FirstGuard);
571ffe93a16SKristof Umann
572ffe93a16SKristof Umann if (FirstAccess->getBeginLoc() < FirstGuard->getBeginLoc())
573ffe93a16SKristof Umann return true;
574ffe93a16SKristof Umann }
575ffe93a16SKristof Umann
576ffe93a16SKristof Umann return false;
577ffe93a16SKristof Umann }
578ffe93a16SKristof Umann
getVariableName(const FieldDecl * Field)579f0dd1016SKristof Umann std::string clang::ento::getVariableName(const FieldDecl *Field) {
58056963aecSKristof Umann // If Field is a captured lambda variable, Field->getName() will return with
58156963aecSKristof Umann // an empty string. We can however acquire it's name from the lambda's
58256963aecSKristof Umann // captures.
58356963aecSKristof Umann const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
58456963aecSKristof Umann
58556963aecSKristof Umann if (CXXParent && CXXParent->isLambda()) {
58656963aecSKristof Umann assert(CXXParent->captures_begin());
58756963aecSKristof Umann auto It = CXXParent->captures_begin() + Field->getFieldIndex();
588f0dd1016SKristof Umann
589f0dd1016SKristof Umann if (It->capturesVariable())
590f0dd1016SKristof Umann return llvm::Twine("/*captured variable*/" +
591f0dd1016SKristof Umann It->getCapturedVar()->getName())
592f0dd1016SKristof Umann .str();
593f0dd1016SKristof Umann
594f0dd1016SKristof Umann if (It->capturesThis())
595f0dd1016SKristof Umann return "/*'this' capture*/";
596f0dd1016SKristof Umann
597f0dd1016SKristof Umann llvm_unreachable("No other capture type is expected!");
59856963aecSKristof Umann }
59956963aecSKristof Umann
600adcd0268SBenjamin Kramer return std::string(Field->getName());
60156963aecSKristof Umann }
60256963aecSKristof Umann
registerUninitializedObjectChecker(CheckerManager & Mgr)60356963aecSKristof Umann void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
60456963aecSKristof Umann auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
605ceb5f654SKristof Umann
6064dc84729SKirstóf Umann const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
6076cec6c46SKristof Umann UninitObjCheckerOptions &ChOpts = Chk->Opts;
6086cec6c46SKristof Umann
60983cc1b35SKristof Umann ChOpts.IsPedantic = AnOpts.getCheckerBooleanOption(Chk, "Pedantic");
610088b1c9cSKristof Umann ChOpts.ShouldConvertNotesToWarnings = AnOpts.getCheckerBooleanOption(
61183cc1b35SKristof Umann Chk, "NotesAsWarnings");
6120a1f91c8SKristof Umann ChOpts.CheckPointeeInitialization = AnOpts.getCheckerBooleanOption(
61383cc1b35SKristof Umann Chk, "CheckPointeeInitialization");
614d6145d98SKristof Umann ChOpts.IgnoredRecordsWithFieldPattern =
615adcd0268SBenjamin Kramer std::string(AnOpts.getCheckerStringOption(Chk, "IgnoreRecordsWithField"));
616ffe93a16SKristof Umann ChOpts.IgnoreGuardedFields =
61783cc1b35SKristof Umann AnOpts.getCheckerBooleanOption(Chk, "IgnoreGuardedFields");
618748c139aSKristof Umann
619748c139aSKristof Umann std::string ErrorMsg;
620748c139aSKristof Umann if (!llvm::Regex(ChOpts.IgnoredRecordsWithFieldPattern).isValid(ErrorMsg))
621748c139aSKristof Umann Mgr.reportInvalidCheckerOptionValue(Chk, "IgnoreRecordsWithField",
622748c139aSKristof Umann "a valid regex, building failed with error message "
623748c139aSKristof Umann "\"" + ErrorMsg + "\"");
62456963aecSKristof Umann }
625058a7a45SKristof Umann
shouldRegisterUninitializedObjectChecker(const CheckerManager & mgr)626bda3dd0dSKirstóf Umann bool ento::shouldRegisterUninitializedObjectChecker(const CheckerManager &mgr) {
627058a7a45SKristof Umann return true;
628058a7a45SKristof Umann }
629