Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -314,6 +314,10 @@ "object will be reported">, DescFile<"MisusedMovedObjectChecker.cpp">; +def CtorUninitializedMemberChecker: Checker<"CtorUninitializedMember">, + HelpText<"Reports uninitialized members in constructors">, + DescFile<"CtorUninitializedMemberChecker.cpp">; + } // end: "alpha.cplusplus" Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -26,6 +26,7 @@ ClangCheckers.cpp CloneChecker.cpp ConversionChecker.cpp + CtorUninitializedMemberChecker.cpp CXXSelfAssignmentChecker.cpp DeadStoresChecker.cpp DebugCheckers.cpp Index: lib/StaticAnalyzer/Checkers/CtorUninitializedMemberChecker.cpp =================================================================== --- /dev/null +++ lib/StaticAnalyzer/Checkers/CtorUninitializedMemberChecker.cpp @@ -0,0 +1,523 @@ +//=======- CtorUninitializedMemberChecker.cpp --------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a checker that checks cunstructors for possibly +// uninitialized fields. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include +#include + +using namespace clang; +using namespace clang::ento; + +namespace { + +/// Represents a field chain. A field chain is a vector of fields where the +/// first element of the chain is the object under checking (not stored), and +/// every other element is a field, and the element that precedes it is the +/// object that contains it. +class FieldChainInfo { + using FieldChain = llvm::SmallVector; + + FieldChain Chain; + // If this is a fieldchain whose last element is an uninitialized region of a + // pointer type, this variable will store whether the pointer itself or the + // pointee is uninitialized. + bool IsDereferenced = false; + +public: + void push_back(const FieldRegion *FR) { Chain.push_back(FR); } + llvm::iterator_range fieldRegions() const { + return llvm::iterator_range(Chain); + } + + bool isPointer() const { + return Chain.back()->getDecl()->getType()->isPointerType(); + } + bool isDereferenced() const; + void dereference() { IsDereferenced = true; } + const FieldDecl *getEndOfChain() const { return Chain.back()->getDecl(); } + StringRef getAsString(SmallString<200> &Buf) const; + friend class FieldChainInfoComparator; +}; + +struct FieldChainInfoComparator { + bool operator()(const FieldChainInfo &lhs, const FieldChainInfo &rhs) { + return lhs.Chain.back() < rhs.Chain.back(); + } +}; + +using UninitFieldSet = std::set; + +class CtorUninitializedMemberChecker : public Checker { + std::unique_ptr BT_uninitField; + +public: + CtorUninitializedMemberChecker() + : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {} + void checkEndFunction(CheckerContext &C) const; + void reportUninitFields(CheckerContext &Context, + const UninitFieldSet &UninitFields) const; +}; + +/// Searches for and stores uninitialized fields in a non-union object. +class FindUninitializedFields { + StoreManager &StoreMgr; + MemRegionManager &MrMgr; + Store S; + const TypedValueRegion *const ObjectR; + bool IsChecked = false; + + UninitFieldSet UninitFields; + +public: + FindUninitializedFields(StoreManager &StoreMgr, MemRegionManager &MrMgr, + Store S, const TypedValueRegion *const R); + bool isFullyInitialized(); + const UninitFieldSet &getUninitFields(); + +private: + void addFieldToUninits(Optional Chain, const FieldDecl *Field, + const FieldRegion *Region); + + // For the purposes of this checker, we'll regard the object under checking as + // a directed tree, where + // * the root is the object under checking + // * every node is an object that is a + // - union + // - non-union record + // - pointer/reference + // - fundamental object (int, double, etc.) + // * the parent of each node is the object that contains it + // * every leaf is a fundamental object, a nullptr or an undefined pointer. + // Example: + // + // struct A { + // struct B { + // int x, y = 0; + // }; + // B b; + // int *iptr = new int; + // B* bptr; + // + // A() {} + // }; + // + // The directed tree: + // + // ->x + // / + // ->b--->y + // / + // A-->iptr->(int value) + // \ + // ->bptr + // + // From this we'll construct a vector of fieldchains, where each fieldchain + // represents an uninitialized field. If the field is a pointer type, we'll + // also store whether the pointer itself or value it points to is uninit. + // In the above example, for the default constructor call we'll end up with + // these fieldchains: + // + // this->b.x + // this->iptr (pointed value uninit) + // this->bptr (pointer uninit) + // + // We'll traverse each node of the above graph with the appropiate one of + // these methods: + bool isUnionUninit(const TypedValueRegion *R); + bool isNonUnionUninit(const TypedValueRegion *R, + const Optional &Chain = None); + bool isPointerOrReferenceUninit(const SVal &V, const FieldRegion *FR, + const FieldDecl *I, + const Optional &Chain = None); + bool isFundamentalUninit(const SVal &V); +}; + +// Utility function declarations. + +/// Returns the with the object that was constructed by CtorDecl, or None if +/// that isn't possible. +Optional +getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context); + +/// Checks whether the constructor under checking is called by another +/// constructor. This avoids essentially the same error being reported multiple +/// times. +bool isCalledByConstructor(const CheckerContext &Context); + +/// Returns true if FD is a void pointer (void*, void**, etc.). +/// We can't know the type of the region that a void pointer points to, so FD +/// can't be analyzed if this function return true for it. +bool isVoidPointer(const FieldDecl *FD); + +} // namespace + +//===----------------------------------------------------------------------===// +// Methods for CtorUninitializedMemberChecker. +//===----------------------------------------------------------------------===// + +void CtorUninitializedMemberChecker::checkEndFunction( + CheckerContext &Context) const { + + const auto *CtorDecl = dyn_cast_or_null( + Context.getLocationContext()->getDecl()); + if (!CtorDecl) + return; + + if (!CtorDecl->isUserProvided()) + return; + + if (CtorDecl->getParent()->isUnion()) + return; + + if (isCalledByConstructor(Context)) + return; + + Optional Object = getObjectVal(CtorDecl, Context); + if (!Object) + return; + + FindUninitializedFields F(Context.getStoreManager(), + Context.getSValBuilder().getRegionManager(), + Object->getStore(), Object->getRegion()); + + if (!F.isFullyInitialized()) + return; + + // There are uninitialized fields in the record. + reportUninitFields(Context, F.getUninitFields()); +} + +void CtorUninitializedMemberChecker::reportUninitFields( + CheckerContext &Context, const UninitFieldSet &UninitFields) const { + + ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState()); + if (!Node) + return; + + PathDiagnosticLocation LocUsedForUniqueing; + const Stmt *CallSite = Context.getStackFrame()->getCallSite(); + if (CallSite) + LocUsedForUniqueing = PathDiagnosticLocation::createBegin( + CallSite, Context.getSourceManager(), Node->getLocationContext()); + + std::string WarningMsg = std::to_string(UninitFields.size()) + + " uninitialized field" + + (UninitFields.size() == 1 ? "" : "s") + + " at the end of the constructor call"; + + auto Report = llvm::make_unique( + *BT_uninitField, WarningMsg, Node, LocUsedForUniqueing, + Node->getLocationContext()->getDecl()); + + for (const auto &FieldChain : UninitFields) { + SmallString<200> FieldChainBuf; + SmallString<200> NoteBuf; + llvm::raw_svector_ostream NoteOS(NoteBuf); + + if (FieldChain.isPointer()) { + if (FieldChain.isDereferenced()) + NoteOS << "uninitialized pointee 'this->"; + else + NoteOS << "uninitialized pointer 'this->"; + } else + NoteOS << "uninitialized field 'this->"; + NoteOS << FieldChain.getAsString(FieldChainBuf); + NoteOS << "'"; + + Report->addNote(NoteOS.str(), + PathDiagnosticLocation::create(FieldChain.getEndOfChain(), + Context.getSourceManager())); + } + + Context.emitReport(std::move(Report)); +} + +//===----------------------------------------------------------------------===// +// Methods for FindUninitializedFields. +//===----------------------------------------------------------------------===// + +FindUninitializedFields::FindUninitializedFields( + StoreManager &StoreMgr, MemRegionManager &MrMgr, Store S, + const TypedValueRegion *const R) + : StoreMgr(StoreMgr), MrMgr(MrMgr), S(S), ObjectR(R) {} + +bool FindUninitializedFields::isFullyInitialized() { + bool ret = isNonUnionUninit(ObjectR, FieldChainInfo()); + IsChecked = true; + return ret; +} + +const UninitFieldSet &FindUninitializedFields::getUninitFields() { + if (!IsChecked) + isFullyInitialized(); + return UninitFields; +} + +// If Chain's value is None, that means that this function was called to +// determine whether a union has any initialized fields. In this case we're not +// collecting fields, we'd only like to know whether the value contained in +// region R is initialized. +bool FindUninitializedFields::isNonUnionUninit( + const TypedValueRegion *R, const Optional &Chain) { + + const RecordDecl *RD = + R->getValueType()->getAs()->getDecl()->getDefinition(); + assert(RD && "Referred record has no definition"); + + bool ContainsUninitField = false; + Optional LocalChain = Chain; + + // Are all of this non-union's fields initialized? + for (const FieldDecl *I : RD->fields()) { + const FieldRegion *FR = MrMgr.getFieldRegion(I, R); + QualType T = I->getType(); + + if (T->isStructureOrClassType()) { + if (LocalChain) + LocalChain->push_back(FR); + if (isNonUnionUninit(FR, LocalChain)) + ContainsUninitField = true; + continue; + } + + if (T->isUnionType()) { + if (isUnionUninit(FR)) { + addFieldToUninits(LocalChain, I, FR); + ContainsUninitField = true; + } + continue; + } + + // At this point the field is a fundamental object, pointer or reference. + SVal V = StoreMgr.getBinding(S, loc::MemRegionVal(FR)); + + // If this is a pointer or reference type. + if (auto LocType = V.getAs()) { + if (isPointerOrReferenceUninit(V, FR, I, LocalChain)) + ContainsUninitField = true; + continue; + } + + // At this point the field is a fundamental type. + if (isFundamentalUninit(V)) { + addFieldToUninits(LocalChain, I, FR); + ContainsUninitField = true; + } + } + + // Checking bases. + const auto *CXXRD = dyn_cast(RD); + if (!CXXRD) + return ContainsUninitField; + + for (const CXXBaseSpecifier BaseSpec : CXXRD->bases()) { + const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl(); + const auto *BaseRegion = + MrMgr.getCXXBaseObjectRegion(Base, R, BaseSpec.isVirtual()); + + if (isNonUnionUninit(BaseRegion, LocalChain)) + ContainsUninitField = true; + } + + return ContainsUninitField; +} + +// TODO As of writing this checker, there is very little support for unions in +// the CSA. This function relies on a nonexisting implementation by assuming as +// little about it as possible. +bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) { + const RecordDecl *RD = + R->getValueType()->getAs()->getDecl()->getDefinition(); + assert(RD && "Referred record has no definition"); + + bool ContainsInitField = false; + auto It = RD->field_begin(), End = RD->field_end(); + + // Does this union contain at least one initalized field? + while (It != End && !ContainsInitField) { + + const FieldRegion *FR = MrMgr.getFieldRegion(*It, R); + QualType T = (*It)->getType(); + + if (T->isStructureOrClassType()) + ContainsInitField = !isNonUnionUninit(FR); + + else if (T->isUnionType()) + ContainsInitField = !isUnionUninit(FR); + + else { + SVal V = StoreMgr.getBinding(S, loc::MemRegionVal(FR)); + + if (auto LocType = V.getAs()) + ContainsInitField = !isPointerOrReferenceUninit(V, FR, *It); + else + ContainsInitField = !isFundamentalUninit(V); + } + + ++It; + } + return !ContainsInitField; +} + +bool FindUninitializedFields::isPointerOrReferenceUninit( + const SVal &V, const FieldRegion *FR, const FieldDecl *FD, + const Optional &Chain) { + + if (V.isUnknown() || V.isZeroConstant()) + return false; + + if (V.isUndef()) { + addFieldToUninits(Chain, FD, FR); + return true; + } + + if (isVoidPointer(FD)) + return false; + + Optional LocalChain = Chain; + + SVal DerefdV = StoreMgr.getBinding(S, V.castAs()); + while (Optional L = DerefdV.getAs()) + DerefdV = StoreMgr.getBinding(S, *L); + + // If V is a pointer pointing to a record type. + if (Optional RecordV = + DerefdV.getAs()) { + + const TypedValueRegion *RT = RecordV->getRegion(); + + // We can't reason about symbolic regions, assume its initialized. + // Note that this also avoids a potential infinite recursion, because + // constructors for list-like classes are checked without being called, and + // the CSA will conjure a symbolic region for Node *next; or similar code + // snippets. + if (RT->getSymbolicBase()) + return false; + + const auto *T = RT->getValueType()->getAs(); + + if (T->isStructureOrClassType()) { + if (LocalChain) + LocalChain->push_back(FR); + return isNonUnionUninit(RT, LocalChain); + } + + if (T->isUnionType()) { + // TODO does control ever reach here? + if (isUnionUninit(RT)) { + if (LocalChain) + LocalChain->dereference(); + addFieldToUninits(LocalChain, FD, FR); + return true; + } + } + } + + // At this point V is a pointer pointing to a fundamental type. + if (isFundamentalUninit(DerefdV)) { + if (LocalChain) + LocalChain->dereference(); + addFieldToUninits(LocalChain, FD, FR); + return true; + } + + return false; +} + +bool FindUninitializedFields::isFundamentalUninit(const SVal &V) { + return V.isUndef(); +} + +void FindUninitializedFields::addFieldToUninits(Optional Chain, + const FieldDecl *Field, + const FieldRegion *Region) { + if (!Chain) + return; + + Chain->push_back(Region); + UninitFields.insert(std::move(*Chain)); +} + +//===----------------------------------------------------------------------===// +// Methods for FieldChainInfo. +//===----------------------------------------------------------------------===// + +bool FieldChainInfo::isDereferenced() const { + assert(isPointer() && "Only pointers may or may not be dereferenced!"); + return IsDereferenced; +} + +StringRef FieldChainInfo::getAsString(SmallString<200> &Buf) const { + llvm::raw_svector_ostream OS(Buf); + for (const FieldRegion *FR : Chain) { + const FieldDecl *Field = FR->getDecl(); + OS << Field->getNameAsString(); + OS << (Field->getType()->isPointerType() ? "->" : "."); + } + + // Remove last "->" or "." from the end of the string. + if (Chain.back()->getDecl()->getType()->isPointerType()) + return OS.str().drop_back(2); + return OS.str().drop_back(1); +} + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +namespace { + +bool isVoidPointer(const FieldDecl *FD) { + QualType T = FD->getType(); + while (T->isPointerType() && !T->isVoidPointerType()) { + T = T->getPointeeType(); + } + return T->isVoidPointerType(); +} + +Optional +getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) { + + Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(), + Context.getStackFrame()); + // getting 'this' + SVal This = Context.getState()->getSVal(ThisLoc); + + // getting '*this' + SVal Object = Context.getState()->getSVal(This.castAs()); + + return Object.getAs(); +} + +bool isCalledByConstructor(const CheckerContext &Context) { + const LocationContext *LC = Context.getLocationContext()->getParent(); + + while (LC) { + if (isa(LC->getDecl())) + return true; + + LC = LC->getParent(); + } + return false; +} + +} // namespace + +void ento::registerCtorUninitializedMemberChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} Index: test/Analysis/ctor-uninitialized-member-inheritance.cpp =================================================================== --- /dev/null +++ test/Analysis/ctor-uninitialized-member-inheritance.cpp @@ -0,0 +1,775 @@ +//RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.CtorUninitializedMember -std=c++11 -verify %s + +//===----------------------------------------------------------------------===// +// Non-polymorphic inheritance tests +//===----------------------------------------------------------------------===// + +class NonPolymorphicLeft1 { + int x; + +protected: + int y; + +public: + NonPolymorphicLeft1() = default; + NonPolymorphicLeft1(int) : x(420) {} +}; + +class NonPolymorphicInheritanceTest1 : public NonPolymorphicLeft1 { + int z; + +public: + NonPolymorphicInheritanceTest1() + : NonPolymorphicLeft1(int{}) { + y = 420; + z = 420; + // All good! + } +}; + +void f00() { + NonPolymorphicInheritanceTest1(); +} + +class NonPolymorphicRight1 { + int x; // expected-note{{uninitialized field 'this->x'}} +protected: + int y; + +public: + NonPolymorphicRight1() = default; + NonPolymorphicRight1(int) : x(420) {} +}; + +class NonPolymorphicInheritanceTest2 : public NonPolymorphicRight1 { + int z; + +public: + NonPolymorphicInheritanceTest2() { + y = 420; + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f01() { + NonPolymorphicInheritanceTest2(); +} + +class NonPolymorphicBaseClass3 { + int x; + +protected: + int y; // expected-note{{uninitialized field 'this->y'}} +public: + NonPolymorphicBaseClass3() = default; + NonPolymorphicBaseClass3(int) : x(420) {} +}; + +class NonPolymorphicInheritanceTest3 : public NonPolymorphicBaseClass3 { + int z; + +public: + NonPolymorphicInheritanceTest3() + : NonPolymorphicBaseClass3(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f02() { + NonPolymorphicInheritanceTest3(); +} + +class NonPolymorphicBaseClass4 { + int x; + +protected: + int y; + +public: + NonPolymorphicBaseClass4() = default; + NonPolymorphicBaseClass4(int) : x(420) {} +}; + +class NonPolymorphicInheritanceTest4 : public NonPolymorphicBaseClass4 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + NonPolymorphicInheritanceTest4() + : NonPolymorphicBaseClass4(int{}) { + y = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f03() { + NonPolymorphicInheritanceTest4(); +} + +//===----------------------------------------------------------------------===// +// Polymorphic inheritance tests +//===----------------------------------------------------------------------===// + +class PolymorphicLeft1 { + int x; + +protected: + int y; + +public: + virtual ~PolymorphicLeft1() = default; + PolymorphicLeft1() = default; + PolymorphicLeft1(int) : x(420) {} +}; + +class PolymorphicInheritanceTest1 : public PolymorphicLeft1 { + int z; + +public: + PolymorphicInheritanceTest1() + : PolymorphicLeft1(int{}) { + y = 420; + z = 420; + // All good! + } +}; + +void f04() { + PolymorphicInheritanceTest1(); +} + +class PolymorphicRight1 { + int x; // expected-note{{uninitialized field 'this->x'}} +protected: + int y; + +public: + virtual ~PolymorphicRight1() = default; + PolymorphicRight1() = default; + PolymorphicRight1(int) : x(420) {} +}; + +class PolymorphicInheritanceTest2 : public PolymorphicRight1 { + int z; + +public: + PolymorphicInheritanceTest2() { + y = 420; + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f05() { + PolymorphicInheritanceTest2(); +} + +class PolymorphicBaseClass3 { + int x; + +protected: + int y; // expected-note{{uninitialized field 'this->y'}} +public: + virtual ~PolymorphicBaseClass3() = default; + PolymorphicBaseClass3() = default; + PolymorphicBaseClass3(int) : x(420) {} +}; + +class PolymorphicInheritanceTest3 : public PolymorphicBaseClass3 { + int z; + +public: + PolymorphicInheritanceTest3() + : PolymorphicBaseClass3(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f06() { + PolymorphicInheritanceTest3(); +} + +class PolymorphicBaseClass4 { + int x; + +protected: + int y; + +public: + virtual ~PolymorphicBaseClass4() = default; + PolymorphicBaseClass4() = default; + PolymorphicBaseClass4(int) : x(420) {} +}; + +class PolymorphicInheritanceTest4 : public PolymorphicBaseClass4 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + PolymorphicInheritanceTest4() + : PolymorphicBaseClass4(int{}) { + y = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f07() { + PolymorphicInheritanceTest4(); +} + +//===----------------------------------------------------------------------===// +// Virtual inheritance tests +//===----------------------------------------------------------------------===// + +class VirtualPolymorphicLeft1 { + int x; + +protected: + int y; + +public: + virtual ~VirtualPolymorphicLeft1() = default; + VirtualPolymorphicLeft1() = default; + VirtualPolymorphicLeft1(int) : x(420) {} +}; + +class VirtualInheritanceTest1 : virtual public VirtualPolymorphicLeft1 { + int z; + +public: + VirtualInheritanceTest1() + : VirtualPolymorphicLeft1(int()) { + y = 420; + z = 420; + // All good! + } +}; + +void f08() { + VirtualInheritanceTest1(); +} + +class VirtualPolymorphicRight1 { + int x; // expected-note{{uninitialized field 'this->x'}} +protected: + int y; + +public: + virtual ~VirtualPolymorphicRight1() = default; + VirtualPolymorphicRight1() = default; + VirtualPolymorphicRight1(int) : x(420) {} +}; + +class VirtualInheritanceTest2 : virtual public VirtualPolymorphicRight1 { + int z; + +public: + VirtualInheritanceTest2() { + y = 420; + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f09() { + VirtualInheritanceTest2(); +} + +class VirtualPolymorphicBaseClass3 { + int x; + +protected: + int y; // expected-note{{uninitialized field 'this->y'}} +public: + virtual ~VirtualPolymorphicBaseClass3() = default; + VirtualPolymorphicBaseClass3() = default; + VirtualPolymorphicBaseClass3(int) : x(420) {} +}; + +class VirtualInheritanceTest3 : virtual public VirtualPolymorphicBaseClass3 { + int z; + +public: + VirtualInheritanceTest3() + : VirtualPolymorphicBaseClass3(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f10() { + VirtualInheritanceTest3(); +} + +//===----------------------------------------------------------------------===// +// Multiple inheritance tests +//===----------------------------------------------------------------------===// + +/* + Left Right + \ / + \ / + \ / + MultipleInheritanceTest +*/ + +struct Left1 { + int x; + Left1() = default; + Left1(int) : x(420) {} +}; +struct Right1 { + int y; + Right1() = default; + Right1(int) : y(420) {} +}; + +class MultipleInheritanceTest1 : public Left1, public Right1 { + int z; + +public: + MultipleInheritanceTest1() + : Left1(int{}), + Right1(char{}) { + z = 420; + // All good! + } + + MultipleInheritanceTest1(int) + : Left1(int{}) { + y = 420; + z = 420; + // All good! + } + + MultipleInheritanceTest1(int, int) + : Right1(char{}) { + x = 420; + z = 420; + // All good! + } +}; + +void f11() { + MultipleInheritanceTest1(); + MultipleInheritanceTest1(int()); + MultipleInheritanceTest1(int(), int()); +} + +struct Left2 { + int x; + Left2() = default; + Left2(int) : x(420) {} +}; +struct Right2 { + int y; // expected-note{{uninitialized field 'this->y'}} + Right2() = default; + Right2(int) : y(420) {} +}; + +class MultipleInheritanceTest2 : public Left2, public Right2 { + int z; + +public: + MultipleInheritanceTest2() + : Left2(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f12() { + MultipleInheritanceTest2(); +} + +struct Left3 { + int x; // expected-note{{uninitialized field 'this->x'}} + Left3() = default; + Left3(int) : x(420) {} +}; +struct Right3 { + int y; + Right3() = default; + Right3(int) : y(420) {} +}; + +class MultipleInheritanceTest3 : public Left3, public Right3 { + int z; + +public: + MultipleInheritanceTest3() + : Right3(char{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f13() { + MultipleInheritanceTest3(); +} + +struct Left4 { + int x; + Left4() = default; + Left4(int) : x(420) {} +}; +struct Right4 { + int y; + Right4() = default; + Right4(int) : y(420) {} +}; + +class MultipleInheritanceTest4 : public Left4, public Right4 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + MultipleInheritanceTest4() + : Left4(int{}), + Right4(char{}) { // expected-warning{{1 uninitialized field}} + } +}; + +void f14() { + MultipleInheritanceTest4(); +} + +struct Left5 { + int x; + Left5() = default; + Left5(int) : x(420) {} +}; +struct Right5 { + int y; // expected-note{{uninitialized field 'this->y'}} + Right5() = default; + Right5(int) : y(420) {} +}; + +class MultipleInheritanceTest5 : public Left5, public Right5 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + MultipleInheritanceTest5() // expected-warning{{2 uninitialized fields}} + : Left5(int{}) { + } +}; + +void f15() { + MultipleInheritanceTest5(); +} + +//===----------------------------------------------------------------------===// +// Non-virtual diamond inheritance tests +//===----------------------------------------------------------------------===// + +/* + NonVirtualBase NonVirtualBase + | | + | | + | | + First Second + \ / + \ / + \ / + NonVirtualDiamondInheritanceTest +*/ + +struct NonVirtualBase1 { + int x; + NonVirtualBase1() = default; + NonVirtualBase1(int) : x(420) {} +}; +struct First1 : public NonVirtualBase1 { + First1() = default; + First1(int) : NonVirtualBase1(int{}) {} +}; +struct Second1 : public NonVirtualBase1 { + Second1() = default; + Second1(int) : NonVirtualBase1(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest1 : public First1, public Second1 { + int z; + +public: + NonVirtualDiamondInheritanceTest1() + : First1(int{}), + Second1(int{}) { + z = 420; + // All good! + } + + NonVirtualDiamondInheritanceTest1(int) + : First1(int{}) { + Second1::x = 420; + z = 420; + // All good! + } + + NonVirtualDiamondInheritanceTest1(int, int) + : Second1(int{}) { + First1::x = 420; + z = 420; + // All good! + } +}; + +void f16() { + NonVirtualDiamondInheritanceTest1(); + NonVirtualDiamondInheritanceTest1(int()); + NonVirtualDiamondInheritanceTest1(int(), int()); +} + +struct NonVirtualBase2 { + int x; // expected-note{{uninitialized field 'this->x'}} + NonVirtualBase2() = default; + NonVirtualBase2(int) : x(420) {} +}; +struct First2 : public NonVirtualBase2 { + First2() = default; + First2(int) : NonVirtualBase2(int{}) {} +}; +struct Second2 : public NonVirtualBase2 { + Second2() = default; + Second2(int) : NonVirtualBase2(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest2 : public First2, public Second2 { + int z; + +public: + NonVirtualDiamondInheritanceTest2() + : First2(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f17() { + NonVirtualDiamondInheritanceTest2(); +} + +struct NonVirtualBase3 { + int x; // expected-note{{uninitialized field 'this->x'}} + NonVirtualBase3() = default; + NonVirtualBase3(int) : x(420) {} +}; +struct First3 : public NonVirtualBase3 { + First3() = default; + First3(int) : NonVirtualBase3(int{}) {} +}; +struct Second3 : public NonVirtualBase3 { + Second3() = default; + Second3(int) : NonVirtualBase3(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest3 : public First3, public Second3 { + int z; + +public: + NonVirtualDiamondInheritanceTest3() + : Second3(int{}) { + z = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f18() { + NonVirtualDiamondInheritanceTest3(); +} + +struct NonVirtualBase4 { + int x; // expected-note{{uninitialized field 'this->x'}} + // expected-note@-1{{uninitialized field 'this->x'}} + NonVirtualBase4() = default; + NonVirtualBase4(int) : x(420) {} +}; +struct First4 : public NonVirtualBase4 { + First4() = default; + First4(int) : NonVirtualBase4(int{}) {} +}; +struct Second4 : public NonVirtualBase4 { + Second4() = default; + Second4(int) : NonVirtualBase4(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest4 : public First4, public Second4 { + int z; + +public: + NonVirtualDiamondInheritanceTest4() { + z = 420; // expected-warning{{2 uninitialized fields}} + } +}; + +void f19() { + NonVirtualDiamondInheritanceTest4(); +} + +struct NonVirtualBase5 { + int x; + NonVirtualBase5() = default; + NonVirtualBase5(int) : x(420) {} +}; +struct First5 : public NonVirtualBase5 { + First5() = default; + First5(int) : NonVirtualBase5(int{}) {} +}; +struct Second5 : public NonVirtualBase5 { + Second5() = default; + Second5(int) : NonVirtualBase5(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest5 : public First5, public Second5 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + NonVirtualDiamondInheritanceTest5() + : First5(int{}), + Second5(int{}) { // expected-warning{{1 uninitialized field}} + } +}; + +void f20() { + NonVirtualDiamondInheritanceTest5(); +} + +struct NonVirtualBase6 { + int x; // expected-note{{uninitialized field 'this->x'}} + NonVirtualBase6() = default; + NonVirtualBase6(int) : x(420) {} +}; +struct First6 : public NonVirtualBase6 { + First6() = default; + First6(int) : NonVirtualBase6(int{}) {} +}; +struct Second6 : public NonVirtualBase6 { + Second6() = default; + Second6(int) : NonVirtualBase6(int{}) {} +}; + +class NonVirtualDiamondInheritanceTest6 : public First6, public Second6 { + int z; // expected-note{{uninitialized field 'this->z'}} + +public: + NonVirtualDiamondInheritanceTest6() // expected-warning{{2 uninitialized fields}} + : First6(int{}) { + // 'z' and 'Second::x' unintialized + } +}; + +void f21() { + NonVirtualDiamondInheritanceTest6(); +} + +//===----------------------------------------------------------------------===// +// Virtual diamond inheritance tests +//===----------------------------------------------------------------------===// + +/* + VirtualBase + / \ + / \ + / \ + VirtualFirst VirtualSecond + \ / + \ / + \ / + NonVirtualDiamondInheritanceTest +*/ + +struct VirtualBase1 { + int x; + VirtualBase1() = default; + VirtualBase1(int) : x(420) {} +}; +struct VirtualFirst1 : virtual public VirtualBase1 { + VirtualFirst1() = default; + VirtualFirst1(int) : VirtualBase1(int{}) {} + VirtualFirst1(int, int) { x = 420; } +}; +struct VirtualSecond1 : virtual public VirtualBase1 { + VirtualSecond1() = default; + VirtualSecond1(int) : VirtualBase1(int{}) {} + VirtualSecond1(int, int) { x = 420; } +}; + +class VirtualDiamondInheritanceTest1 : public VirtualFirst1, public VirtualSecond1 { + +public: + VirtualDiamondInheritanceTest1() { + x = 0; + // All good! + } + + VirtualDiamondInheritanceTest1(int) + : VirtualFirst1(int{}, int{}), + VirtualSecond1(int{}, int{}) { + // All good! + } + + VirtualDiamondInheritanceTest1(int, int) + : VirtualFirst1(int{}, int{}) { + // All good! + } +}; + +void f22() { + VirtualDiamondInheritanceTest1(); + VirtualDiamondInheritanceTest1(int()); + VirtualDiamondInheritanceTest1(int(), int()); +} + +struct VirtualBase2 { + int x; // expected-note{{uninitialized field 'this->x'}} + VirtualBase2() = default; + VirtualBase2(int) : x(420) {} +}; +struct VirtualFirst2 : virtual public VirtualBase2 { + VirtualFirst2() = default; + VirtualFirst2(int) : VirtualBase2(int{}) {} + VirtualFirst2(int, int) { x = 420; } +}; +struct VirtualSecond2 : virtual public VirtualBase2 { + VirtualSecond2() = default; + VirtualSecond2(int) : VirtualBase2(int{}) {} + VirtualSecond2(int, int) { x = 420; } +}; + +class VirtualDiamondInheritanceTest2 : public VirtualFirst2, public VirtualSecond2 { + +public: + VirtualDiamondInheritanceTest2() // expected-warning{{1 uninitialized field}} + : VirtualFirst2(int{}) { + // From the N4659 C++ Standard Working Draft: + // + // (15.6.2.7) + // [...] A 'mem-initializer' where the 'mem-initializer-id' denotes a + // virtual base class is ignored during execution of a constructor of any + // class that is not the most derived class. + // + // This means that Left1::x will not be initialized, because in both + // VirtualFirst::VirtualFirst(int) and VirtualSecond::VirtualSecond(int) + // the constructor delegation to Left1::Left1(int) will be + // ignored. + } +}; + +void f23() { + VirtualDiamondInheritanceTest2(); +} + +struct VirtualBase3 { + int x; // expected-note{{uninitialized field 'this->x'}} + VirtualBase3() = default; + VirtualBase3(int) : x(420) {} +}; +struct VirtualFirst3 : virtual public VirtualBase3 { + VirtualFirst3() = default; + VirtualFirst3(int) : VirtualBase3(int{}) {} + VirtualFirst3(int, int) { x = 420; } +}; +struct VirtualSecond3 : virtual public VirtualBase3 { + VirtualSecond3() = default; + VirtualSecond3(int) : VirtualBase3(int{}) {} + VirtualSecond3(int, int) { x = 420; } +}; + +class VirtualDiamondInheritanceTest3 : public VirtualFirst3, public VirtualSecond3 { + +public: + VirtualDiamondInheritanceTest3() // expected-warning{{1 uninitialized field}} + : VirtualFirst3(int{}) {} +}; + +void f24() { + VirtualDiamondInheritanceTest3(); +} Index: test/Analysis/ctor-uninitialized-member.cpp =================================================================== --- /dev/null +++ test/Analysis/ctor-uninitialized-member.cpp @@ -0,0 +1,870 @@ +//RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.CtorUninitializedMember -std=c++11 -verify %s + +//===----------------------------------------------------------------------===// +// Default constructor test. +//===----------------------------------------------------------------------===// + +class DefaultConstructorTest { + int a, b, c, d, e, f, g, h, i, j; + +public: + DefaultConstructorTest() = default; +}; + +void f00() { + DefaultConstructorTest(); +} + +//===----------------------------------------------------------------------===// +// Initializer list test. +//===----------------------------------------------------------------------===// + +class InitListTest1 { + int a; + int b; + +public: + InitListTest1() + : a(420), + b(420) { + // All good! + } +}; + +void f01() { + InitListTest1(); +} + +class InitListTest2 { + int a; + int b; // expected-note{{uninitialized field 'this->b'}} + +public: + InitListTest2() + : a(420) {} // expected-warning{{1 uninitialized field}} +}; + +void f02() { + InitListTest2(); +} + +class InitListTest3 { + int a; // expected-note{{uninitialized field 'this->a'}} + int b; + +public: + InitListTest3() + : b(420) {} // expected-warning{{1 uninitialized field}} +}; + +void f03() { + InitListTest3(); +} + +//===----------------------------------------------------------------------===// +// Constructor body test. +//===----------------------------------------------------------------------===// + +class CtorBodyTest1 { + int a, b; + +public: + CtorBodyTest1() { + a = 420; + b = 420; + // All good! + } +}; + +void f04() { + CtorBodyTest1(); +} + +class CtorBodyTest2 { + int a; + int b; // expected-note{{uninitialized field 'this->b'}} + +public: + CtorBodyTest2() { + a = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f05() { + CtorBodyTest2(); +} + +class CtorBodyTest3 { + int a; // expected-note{{uninitialized field 'this->a'}} + int b; + +public: + CtorBodyTest3() { + b = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f06() { + CtorBodyTest3(); +} + +class CtorBodyTest4 { + int a; // expected-note{{uninitialized field 'this->a'}} + int b; // expected-note{{uninitialized field 'this->b'}} + +public: + CtorBodyTest4() {} +}; + +void f07() { + CtorBodyTest4(); // expected-warning{{2 uninitialized fields}} +} + +//===----------------------------------------------------------------------===// +// Constructor delegation test. +//===----------------------------------------------------------------------===// + +class CtorDelegationTest1 { + int a; + int b; + +public: + CtorDelegationTest1(int) + : a(420) { + // leaves 'b' unintialized, but we'll never check this function + } + + CtorDelegationTest1() + : CtorDelegationTest1(int{}) { // Initializing 'a' + b = 420; + // All good! + } +}; + +void f08() { + CtorDelegationTest1(); +} + +class CtorDelegationTest2 { + int a; // expected-note{{uninitialized field 'this->a'}} + int b; + +public: + CtorDelegationTest2(int) + : b(420) { + // leaves 'a' unintialized, but we'll never check this function + } + + CtorDelegationTest2() + : CtorDelegationTest2(int{}) { // expected-warning{{1 uninitialized field}} + } +}; + +void f09() { + CtorDelegationTest2(); +} + +//===----------------------------------------------------------------------===// +// Tests for classes containing records. +//===----------------------------------------------------------------------===// + +class ContainsRecordTest1 { + struct RecordType { + int x; + int y; + } rec; + int c, d; + +public: + ContainsRecordTest1() + : rec({420, 420}), + c(420), + d(420) { + // All good! + } +}; + +void f10() { + ContainsRecordTest1(); +} + +class ContainsRecordTest2 { + struct RecordType { + int x; + int y; // expected-note{{uninitialized field 'this->rec.y'}} + } rec; + int c, d; + +public: + ContainsRecordTest2() + : c(420), + d(420) { + rec.x = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f11() { + ContainsRecordTest2(); +} + +class ContainsRecordTest3 { + struct RecordType { + int x; // expected-note{{uninitialized field 'this->rec.x'}} + int y; // expected-note{{uninitialized field 'this->rec.y'}} + } rec; + int c, d; + +public: + ContainsRecordTest3() + : c(420), + d(420) { // expected-warning{{2 uninitialized fields}} + } +}; + +void f12() { + ContainsRecordTest3(); +} + +//===----------------------------------------------------------------------===// +// Tests for template classes. +//===----------------------------------------------------------------------===// + +template +class IntTemplateClassTest1 { + T t; + int b; + +public: + IntTemplateClassTest1(T i) { + b = 420; + t = i; + // All good! + } +}; + +void f13() { + IntTemplateClassTest1(420); +} + +template +class IntTemplateClassTest2 { + T t; // expected-note{{uninitialized field 'this->t'}} + int b; + +public: + IntTemplateClassTest2() { + b = 420; // expected-warning{{1 uninitialized field}} + } +}; + +void f14() { + IntTemplateClassTest2(); +} + +struct Record { + int x; // expected-note{{uninitialized field 'this->t.x'}} + int y; // expected-note{{uninitialized field 'this->t.y'}} +}; + +template +class RecordTemplateClassTest { + T t; + int b; + +public: + RecordTemplateClassTest() { + b = 420; // expected-warning{{2 uninitialized fields}} + } +}; + +void f15() { + RecordTemplateClassTest(); +} + +//===----------------------------------------------------------------------===// +// Tests for classes containing pointers. +//===----------------------------------------------------------------------===// + +class NullPtrTest { + struct RecordType { + int x; + int y; + }; + + float *fptr = nullptr; + int *ptr; + RecordType *recPtr; + +public: + NullPtrTest() : ptr(nullptr), recPtr(nullptr) { + // All good! + } +}; + +void f16() { + NullPtrTest(); +} + +class HeapPointerTest1 { + struct RecordType { + int x; //xpected-note{{uninitialized field 'this->recPtr->x'}} + int y; //xpected-note{{uninitialized field 'this->recPtr->y'}} + }; + + float *fptr = new float; //xpected-note{{uninitialized pointee 'this->fptr'}} + int *ptr; //xpected-note{{uninitialized pointee 'this->ptr'}} + RecordType *recPtr; + +public: + HeapPointerTest1() : ptr(new int), recPtr(new RecordType) { //xpected-warning{{3 uninitialized fields}} + } +}; + +void f17() { + HeapPointerTest1(); +} + +class HeapPointerTest2 { + struct RecordType { + int x; + int y; + }; + + float *fptr = new float(); // initializes to 0 + int *ptr; + RecordType *recPtr; + +public: + HeapPointerTest2() : ptr(new int{420}), recPtr(new RecordType{420, 420}) { + // All good! + } +}; + +void f18() { + HeapPointerTest2(); +} + +class StackPointerTest1 { +public: + struct RecordType { + int x; + int y; + }; + +private: + int *ptr; + RecordType *recPtr; + +public: + StackPointerTest1(int *_ptr, StackPointerTest1::RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { + // All good! + } +}; + +void f19() { + int ok_a = 420; + StackPointerTest1::RecordType ok_rec{420, 420}; + StackPointerTest1(&ok_a, &ok_rec); // 'a', 'rec.x', 'rec.y' uninitialized +} + +class StackPointerTest2 { +public: + struct RecordType { + int x; // expected-note{{uninitialized field 'this->recPtr->x'}} + int y; // expected-note{{uninitialized field 'this->recPtr->y'}} + }; + +private: + int *ptr; // expected-note{{uninitialized pointee 'this->ptr'}} + RecordType *recPtr; + +public: + StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { // expected-warning{{3 uninitialized fields}} + } +}; + +void f20() { + int a; + StackPointerTest2::RecordType rec; + StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized +} + +class UninitPointerTest { + struct RecordType { + int x; + int y; + }; + + int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}} + RecordType *recPtr; + +public: + UninitPointerTest() : recPtr(new RecordType{13, 13}) { // expected-warning{{1 uninitialized field}} + } +}; + +void f21() { + UninitPointerTest(); +} + +class VoidPointerTest { + void *vptr; + +public: + VoidPointerTest(void *vptr, char) : vptr(vptr) { + // All good! + } +}; + +void *malloc(int size); + +void f23() { + void *vptr = malloc(sizeof(int)); + VoidPointerTest(vptr, char()); +} + +class MultiPointerTest1 { +public: + struct RecordType { + int x; + int y; + }; + +private: + RecordType **mptr; // expected-note{{uninitialized pointee 'this->mptr'}} + +public: + MultiPointerTest1(RecordType **p, int) : mptr(p) { // expected-warning{{1 uninitialized field}} + } +}; + +void f25() { + MultiPointerTest1::RecordType *p1; + MultiPointerTest1::RecordType **mptr = &p1; + MultiPointerTest1(mptr, int()); // '*mptr' uninitialized +} + +class MultiPointerTest2 { +public: + struct RecordType { + int x; // expected-note{{uninitialized field 'this->mptr->x'}} + int y; // expected-note{{uninitialized field 'this->mptr->y'}} + }; + +private: + RecordType **mptr; + +public: + MultiPointerTest2(RecordType **p, int) : mptr(p) { // expected-warning{{2 uninitialized fields}} + } +}; + +void f26() { + MultiPointerTest2::RecordType i; + MultiPointerTest2::RecordType *p1 = &i; + MultiPointerTest2::RecordType **mptr = &p1; + MultiPointerTest2(mptr, int()); // '**mptr' uninitialized +} + +class MultiPointerTest3 { +public: + struct RecordType { + int x; + int y; + }; + +private: + RecordType **mptr; + +public: + MultiPointerTest3(RecordType **p, int) : mptr(p) { + // All good! + } +}; + +void f27() { + MultiPointerTest3::RecordType i{420, 420}; + MultiPointerTest3::RecordType *p1 = &i; + MultiPointerTest3::RecordType **mptr = &p1; + MultiPointerTest3(mptr, int()); // '**mptr' uninitialized +} + +class ListTest1 { +public: + struct Node { + Node *next = nullptr; // no crash + int i; + }; + +private: + Node *head = nullptr; + +public: + ListTest1() { + // All good! + } +}; + +void f28() { + ListTest1(); +} + +class ListTest2 { +public: + struct Node { + Node *next = nullptr; + int i; // expected-note{{uninitialized field 'this->head->i'}} + }; + +private: + Node *head = nullptr; + +public: + ListTest2(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}} + } +}; + +void f29() { + ListTest2::Node n; + ListTest2(&n, int()); +} + +//===----------------------------------------------------------------------===// +// Tests for classes containing references. +//===----------------------------------------------------------------------===// + +class ReferenceTest1 { +public: + struct RecordType { + int x; + int y; + }; + +private: + RecordType &lref; + RecordType &&rref; + +public: + ReferenceTest1(RecordType &lref, RecordType &rref) : lref(lref), rref(static_cast(rref)) { + // All good! + } +}; + +void f30() { + ReferenceTest1::RecordType d{420, 420}; + ReferenceTest1(d, d); +} + +class ReferenceTest2 { +public: + struct RecordType { + int x; // expected-note{{uninitialized field 'this->lref.x'}} + int y; // expected-note{{uninitialized field 'this->lref.y'}} + }; + +private: + RecordType &lref; + RecordType &&rref; + +public: + ReferenceTest2(RecordType &lref, RecordType &rref) + : lref(lref), rref(static_cast(rref)) { // expected-warning{{2 uninitialized fields}} + } +}; + +void f31() { + ReferenceTest2::RecordType c; + ReferenceTest2(c, c); +} + +class ReferenceTest3 { +public: + struct RecordType { + int x; // expected-note{{uninitialized field 'this->lref.x'}} + int y; // expected-note{{uninitialized field 'this->lref.y'}} + }; + +private: + RecordType &lref; + RecordType &&rref; + +public: + ReferenceTest3(RecordType &lref, RecordType &rref) + : lref(lref), rref(static_cast(rref)) { // expected-warning{{2 uninitialized fields}} + } +}; + +void f32() { + ReferenceTest3::RecordType c, d{420, 420}; + ReferenceTest3(c, d); +} + +class ReferenceTest4 { +public: + struct RecordType { + int x; // expected-note{{uninitialized field 'this->rref.x'}} + int y; // expected-note{{uninitialized field 'this->rref.y'}} + }; + +private: + RecordType &lref; + RecordType &&rref; + +public: + ReferenceTest4(RecordType &lref, RecordType &rref) + : lref(lref), rref(static_cast(rref)) { // expected-warning{{2 uninitialized fields}} + } +}; + +void f33() { + ReferenceTest4::RecordType c, d{420, 420}; + ReferenceTest4(d, c); +} + +//===----------------------------------------------------------------------===// +// Tests for classes containing unions. +//===----------------------------------------------------------------------===// + +template +void mayInitialize(T &); + +template +void wontInitialize(const T &); + +class PassingToUnknownFunctionTest1 { + int a, b; + +public: + PassingToUnknownFunctionTest1() { + mayInitialize(a); + mayInitialize(b); + // All good! + } + + PassingToUnknownFunctionTest1(int) { + mayInitialize(a); + // All good! + } + + PassingToUnknownFunctionTest1(int, int) { + mayInitialize(*this); + // All good! + } +}; + +void f34() { + PassingToUnknownFunctionTest1(); + PassingToUnknownFunctionTest1(int()); + PassingToUnknownFunctionTest1(int(), int()); +} + +class PassingToUnknownFunctionTest2 { + int a; // expected-note{{uninitialized field 'this->a'}} + int b; + +public: + PassingToUnknownFunctionTest2() { + wontInitialize(a); + b = 4; // expected-warning{{1 uninitialized field}} + } +}; + +void f35() { + PassingToUnknownFunctionTest2(); +} + +//===----------------------------------------------------------------------===// +// Tests for classes containing unions. +//===----------------------------------------------------------------------===// + +// FIXME As of writing this checker, there is no good support for union types in +// the CSA. Here is non-exhaustive list of cases. +// Note that the rules for unions are different in C++ and C. +// http://lists.llvm.org/pipermail/cfe-dev/242017-March/42052912.html + +class ContainsSimpleUnionTest1 { + union SimpleUnion { + float uf; + int ui; + char uc; + } u; + +public: + ContainsSimpleUnionTest1() { + u.uf = 3.14; + // All good! + } +}; + +void f36() { + ContainsSimpleUnionTest1(); +} + +class ContainsSimpleUnionTest2 { + union SimpleUnion { + float uf; + int ui; + char uc; + } u; // xpected-note{{uninitialized field 'this->u'}} + +public: + ContainsSimpleUnionTest2() {} +}; + +void f37() { + ContainsSimpleUnionTest2(); // xpected-warning{{1 uninitialized field}} +} + +class UnionPointerTest1 { +public: + union SimpleUnion { + float uf; + int ui; + char uc; + }; + +private: + SimpleUnion *uptr; + +public: + UnionPointerTest1(SimpleUnion *uptr, int) : uptr(uptr) { + // All good! + } +}; + +void f38() { + UnionPointerTest1::SimpleUnion u; + u.uf = 420; + UnionPointerTest1(&u, int()); +} + +class UnionPointerTest2 { +public: + union SimpleUnion { + float uf; + int ui; + char uc; + }; + +private: + SimpleUnion *uptr; // xpected-note{{uninitialized pointee 'this->uptr'}} + +public: + UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {} +}; + +void f39() { + UnionPointerTest2::SimpleUnion u; + UnionPointerTest2(&u, int()); // xpected-warning{{1 uninitialized field}} +} + +class ContainsUnionWithRecordTest1 { + union UnionWithRecord { + struct RecordType { + int x; + int y; + } us; + double ud; + long ul; + + UnionWithRecord(){}; + } u; + +public: + ContainsUnionWithRecordTest1() { + u.ud = 3.14; + // All good! + } +}; + +void f40() { + ContainsUnionWithRecordTest1(); +} + +class ContainsUnionWithRecordTest2 { + union UnionWithRecord { + struct RecordType { + int x; + int y; + } us; + double ud; + long ul; + + UnionWithRecord(){}; + } u; + +public: + ContainsUnionWithRecordTest2() { + u.us = UnionWithRecord::RecordType{420, 420}; + // All good! + } +}; + +void f41() { + ContainsUnionWithRecordTest1(); +} + +class ContainsUnionWithRecordTest3 { + union UnionWithRecord { + struct RecordType { + int x; + int y; + } us; + double ud; + long ul; + + UnionWithRecord(){}; + } u; // xpected-note{{uninitialized field 'this->u'}} + +public: + ContainsUnionWithRecordTest3() { + UnionWithRecord::RecordType rec; + rec.x = 420; + u.us = rec; // xpected-warning{{1 uninitialized field}} + } +}; + +void f42() { + ContainsUnionWithRecordTest3(); +} + +class ContainsUnionWithSimpleUnionTest1 { + union UnionWithSimpleUnion { + union SimpleUnion { + float uf; + int ui; + char uc; + } usu; + long ul; + unsigned uu; + } u; + +public: + ContainsUnionWithSimpleUnionTest1() { + u.usu.ui = 5; + // All good! + } +}; + +void f43() { + ContainsUnionWithSimpleUnionTest1(); +} + +class ContainsUnionWithSimpleUnionTest2 { + union UnionWithSimpleUnion { + union SimpleUnion { + float uf; + int ui; + char uc; + } usu; + long ul; + unsigned uu; + } u; // xpected-note{{uninitialized field 'this->u'}} + +public: + ContainsUnionWithSimpleUnionTest2() {} +}; + +void f44() { + ContainsUnionWithSimpleUnionTest2(); // xpected-warning{{1 uninitialized field}} +}