r334935 - [analyzer] Checker for uninitialized C++ objects
Mikael Holmén via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 18 23:28:05 PDT 2018
Hi Kristof,
Building without asserts (-DNDEBUG) I get the following warning/error
with this commit:
[3082/3387] Building CXX object
tools/clang/lib/StaticAnalyzer/Checkers...eFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.
FAILED:
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o
/repo/app/clang/3.6/bin/clang++ -march=corei7 -DGTEST_HAS_RTTI=0
-D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
-D__STDC_LIMIT_MACROS -Itools/clang/lib/StaticAnalyzer/Checkers
-I../tools/clang/lib/StaticAnalyzer/Checkers -I../tools/clang/include
-Itools/clang/include -I/usr/include/libxml2 -Iinclude -I../include
-I/repo/app/valgrind/3.11.0/include -fPIC -fvisibility-inlines-hidden
-Werror -Werror=date-time -std=c++11 -Wall -Wextra -Wno-unused-parameter
-Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic
-Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor
-Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color
-ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual
-Wno-nested-anon-types -O3 -DNDEBUG -fno-exceptions -fno-rtti -MMD
-MT
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o
-MF
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o.d
-o
tools/clang/lib/StaticAnalyzer/Checkers/CMakeFiles/clangStaticAnalyzerCheckers.dir/UninitializedObjectChecker.cpp.o
-c ../tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
../tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:215:6:
error: unused function 'isPrimitiveType' [-Werror,-Wunused-function]
bool isPrimitiveType(const QualType &T) {
^
1 error generated.
Regards,
Mikael
On 06/18/2018 01:50 PM, Kristof Umann via cfe-commits wrote:
> Author: szelethus
> Date: Mon Jun 18 04:50:17 2018
> New Revision: 334935
>
> URL: http://llvm.org/viewvc/llvm-project?rev=334935&view=rev
> Log:
> [analyzer] Checker for uninitialized C++ objects
>
> This checker analyzes C++ constructor calls, and reports uninitialized fields.
>
> Due to the nature of this problem (uninitialized fields after an object
> construction), this checker doesn't search for bugs, but rather is a tool to
> enforce a specific programming model where every field needs to be initialized.
>
> This checker lands in alpha for now, and a number of followup patches will be
> made to reduce false negatives and to make it easier for the user to understand
> what rules the checker relies on, eg. whether a derived class' constructor is
> responsible for initializing inherited data members or whether it should be
> handled in the base class' constructor.
>
> Differential Revision: https://reviews.llvm.org/D45532
>
> Added:
> cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
> cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
> cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
> cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
> cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp
> Modified:
> cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
> cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
>
> Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=334935&r1=334934&r2=334935&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original)
> +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Mon Jun 18 04:50:17 2018
> @@ -319,6 +319,10 @@ def MisusedMovedObjectChecker: Checker<"
> "object will be reported">,
> DescFile<"MisusedMovedObjectChecker.cpp">;
>
> +def UninitializedObjectChecker: Checker<"UninitializedObject">,
> + HelpText<"Reports uninitialized fields after object construction">,
> + DescFile<"UninitializedObjectChecker.cpp">;
> +
> } // end: "alpha.cplusplus"
>
>
>
> Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=334935&r1=334934&r2=334935&view=diff
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Mon Jun 18 04:50:17 2018
> @@ -92,6 +92,7 @@ add_clang_library(clangStaticAnalyzerChe
> UndefResultChecker.cpp
> UndefinedArraySubscriptChecker.cpp
> UndefinedAssignmentChecker.cpp
> + UninitializedObjectChecker.cpp
> UnixAPIChecker.cpp
> UnreachableCodeChecker.cpp
> VforkChecker.cpp
>
> Added: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp (added)
> +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp Mon Jun 18 04:50:17 2018
> @@ -0,0 +1,669 @@
> +//===----- UninitializedObjectChecker.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 reports uninitialized fields in objects
> +// created after a constructor call.
> +//
> +// This checker has an option "Pedantic" (boolean). If its not set or is set to
> +// false, the checker won't emit warnings for objects that don't have at least
> +// one initialized field. This may be set with
> +// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "ClangSACheckers.h"
> +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
> +#include "clang/StaticAnalyzer/Core/Checker.h"
> +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
> +#include <algorithm>
> +
> +using namespace clang;
> +using namespace clang::ento;
> +
> +namespace {
> +
> +class UninitializedObjectChecker : public Checker<check::EndFunction> {
> + std::unique_ptr<BuiltinBug> BT_uninitField;
> +
> +public:
> + bool IsPedantic; // Will be initialized when registering the checker.
> +
> + UninitializedObjectChecker()
> + : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
> + void checkEndFunction(CheckerContext &C) const;
> +};
> +
> +llvm::ImmutableListFactory<const FieldRegion *> Factory;
> +
> +/// 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.
> +///
> +/// Note that this class is immutable, and new fields may only be added through
> +/// constructor calls.
> +class FieldChainInfo {
> + using FieldChain = llvm::ImmutableList<const FieldRegion *>;
> +
> + FieldChain Chain;
> +
> + const bool IsDereferenced = false;
> +
> +public:
> + FieldChainInfo() = default;
> +
> + FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
> + : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
> +
> + FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
> + const bool IsDereferenced = false);
> +
> + bool contains(const FieldRegion *FR) const { return Chain.contains(FR); }
> + bool isPointer() const;
> +
> + /// If this is a fieldchain whose last element is an uninitialized region of a
> + /// pointer type, `IsDereferenced` will store whether the pointer itself or
> + /// the pointee is uninitialized.
> + bool isDereferenced() const;
> + const FieldDecl *getEndOfChain() const;
> + void print(llvm::raw_ostream &Out) const;
> +
> +private:
> + /// Prints every element except the last to `Out`. Since ImmutableLists store
> + /// elements in reverse order, and have no reverse iterators, we use a
> + /// recursive function to print the fieldchain correctly. The last element in
> + /// the chain is to be printed by `print`.
> + static void printTail(llvm::raw_ostream &Out,
> + const llvm::ImmutableListImpl<const FieldRegion *> *L);
> + friend struct FieldChainInfoComparator;
> +};
> +
> +struct FieldChainInfoComparator {
> + bool operator()(const FieldChainInfo &lhs, const FieldChainInfo &rhs) {
> + assert(!lhs.Chain.isEmpty() && !rhs.Chain.isEmpty() &&
> + "Attempted to store an empty fieldchain!");
> + return *lhs.Chain.begin() < *rhs.Chain.begin();
> + }
> +};
> +
> +using UninitFieldSet = std::set<FieldChainInfo, FieldChainInfoComparator>;
> +
> +/// Searches for and stores uninitialized fields in a non-union object.
> +class FindUninitializedFields {
> + ProgramStateRef State;
> + const TypedValueRegion *const ObjectR;
> +
> + const bool IsPedantic;
> + bool IsAnyFieldInitialized = false;
> +
> + UninitFieldSet UninitFields;
> +
> +public:
> + FindUninitializedFields(ProgramStateRef State,
> + const TypedValueRegion *const R, bool IsPedantic);
> + const UninitFieldSet &getUninitFields();
> +
> +private:
> + /// Adds a FieldChainInfo object to UninitFields. Return true if an insertion
> + /// took place.
> + bool addFieldToUninits(FieldChainInfo LocalChain);
> +
> + // 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
> + // - a non-union record
> + // - a pointer/reference
> + // - an array
> + // - of a member pointer type
> + // - of a primitive type, which we'll define as either a BuiltinType or
> + // EnumeralType.
> + // * the parent of each node is the object that contains it
> + // * every leaf is an array, a primitive object, a member pointer, 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. An uninitialized field may be a
> + // primitive object, a member pointer, a pointer, a pointee or a union without
> + // a single initialized field.
> + // In the above example, for the default constructor call we'll end up with
> + // these fieldchains:
> + //
> + // this->b.x
> + // this->iptr (pointee uninit)
> + // this->bptr (pointer uninit)
> + //
> + // We'll traverse each node of the above graph with the appropiate one of
> + // these methods:
> +
> + /// This method checks a region of a union object, and returns true if no
> + /// field is initialized within the region.
> + bool isUnionUninit(const TypedValueRegion *R);
> +
> + /// This method checks a region of a non-union object, and returns true if
> + /// an uninitialized field is found within the region.
> + bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
> +
> + /// This method checks a region of a pointer or reference object, and returns
> + /// true if the ptr/ref object itself or any field within the pointee's region
> + /// is uninitialized.
> + bool isPointerOrReferenceUninit(const FieldRegion *FR,
> + FieldChainInfo LocalChain);
> +
> + /// This method checks a region of MemberPointerType, and returns true if the
> + /// the pointer is uninitialized.
> + bool isMemberPointerUninit(const FieldRegion *FR, FieldChainInfo LocalChain);
> +
> + /// This method returns true if the value of a primitive object is
> + /// uninitialized.
> + bool isPrimitiveUninit(const SVal &V);
> +
> + // Note that we don't have a method for arrays -- the elements of an array are
> + // often left uninitialized intentionally even when it is of a C++ record
> + // type, so we'll assume that an array is always initialized.
> + // TODO: Add a support for nonloc::LocAsInteger.
> +};
> +
> +// Utility function declarations.
> +
> +/// Returns the object that was constructed by CtorDecl, or None if that isn't
> +/// possible.
> +Optional<nonloc::LazyCompoundVal>
> +getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
> +
> +/// Checks whether the constructor under checking is called by another
> +/// constructor.
> +bool isCalledByConstructor(const CheckerContext &Context);
> +
> +/// Returns whether FD can be (transitively) dereferenced to a void pointer type
> +/// (void*, void**, ...). The type of the region behind a void pointer isn't
> +/// known, and thus FD can not be analyzed.
> +bool isVoidPointer(const FieldDecl *FD);
> +
> +/// Returns true if T is a primitive type. We'll call a type primitive if it's
> +/// either a BuiltinType or an EnumeralType.
> +bool isPrimitiveType(const QualType &T) {
> + return T->isBuiltinType() || T->isEnumeralType();
> +}
> +
> +} // end of anonymous namespace
> +
> +//===----------------------------------------------------------------------===//
> +// Methods for UninitializedObjectChecker.
> +//===----------------------------------------------------------------------===//
> +
> +void UninitializedObjectChecker::checkEndFunction(
> + CheckerContext &Context) const {
> +
> + const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
> + Context.getLocationContext()->getDecl());
> + if (!CtorDecl)
> + return;
> +
> + if (!CtorDecl->isUserProvided())
> + return;
> +
> + if (CtorDecl->getParent()->isUnion())
> + return;
> +
> + // This avoids essentially the same error being reported multiple times.
> + if (isCalledByConstructor(Context))
> + return;
> +
> + Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context);
> + if (!Object)
> + return;
> +
> + FindUninitializedFields F(Context.getState(), Object->getRegion(),
> + IsPedantic);
> +
> + const UninitFieldSet &UninitFields = F.getUninitFields();
> +
> + if (UninitFields.empty())
> + return;
> +
> + // There are uninitialized fields in the record.
> +
> + 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());
> +
> + SmallString<100> WarningBuf;
> + llvm::raw_svector_ostream WarningOS(WarningBuf);
> + WarningOS << UninitFields.size() << " uninitialized field"
> + << (UninitFields.size() == 1 ? "" : "s")
> + << " at the end of the constructor call";
> +
> + auto Report = llvm::make_unique<BugReport>(
> + *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
> + Node->getLocationContext()->getDecl());
> +
> + // TODO: As of now, one warning is emitted per constructor call, and the
> + // uninitialized fields are listed in notes. Until there's a better support
> + // for notes avaible, a note-less version of this checker should be
> + // implemented.
> + for (const auto &FieldChain : UninitFields) {
> + 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->";
> + FieldChain.print(NoteOS);
> + NoteOS << "'";
> +
> + Report->addNote(NoteOS.str(),
> + PathDiagnosticLocation::create(FieldChain.getEndOfChain(),
> + Context.getSourceManager()));
> + }
> +
> + Context.emitReport(std::move(Report));
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Methods for FindUninitializedFields.
> +//===----------------------------------------------------------------------===//
> +
> +FindUninitializedFields::FindUninitializedFields(
> + ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic)
> + : State(State), ObjectR(R), IsPedantic(IsPedantic) {}
> +
> +const UninitFieldSet &FindUninitializedFields::getUninitFields() {
> + isNonUnionUninit(ObjectR, FieldChainInfo());
> +
> + if (!IsPedantic && !IsAnyFieldInitialized)
> + UninitFields.clear();
> +
> + return UninitFields;
> +}
> +
> +bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
> + if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
> + Chain.getEndOfChain()->getLocation()))
> + return false;
> +
> + return UninitFields.insert(Chain).second;
> +}
> +
> +bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
> + FieldChainInfo LocalChain) {
> + assert(R->getValueType()->isRecordType() &&
> + !R->getValueType()->isUnionType() &&
> + "This method only checks non-union record objects!");
> +
> + const RecordDecl *RD =
> + R->getValueType()->getAs<RecordType>()->getDecl()->getDefinition();
> + assert(RD && "Referred record has no definition");
> +
> + bool ContainsUninitField = false;
> +
> + // Are all of this non-union's fields initialized?
> + for (const FieldDecl *I : RD->fields()) {
> +
> + const auto FieldVal =
> + State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
> + const auto *FR = FieldVal.getRegionAs<FieldRegion>();
> + QualType T = I->getType();
> +
> + // If LocalChain already contains FR, then we encountered a cyclic
> + // reference. In this case, region FR is already under checking at an
> + // earlier node in the directed tree.
> + if (LocalChain.contains(FR))
> + return false;
> +
> + if (T->isStructureOrClassType()) {
> + if (isNonUnionUninit(FR, {LocalChain, FR}))
> + ContainsUninitField = true;
> + continue;
> + }
> +
> + if (T->isUnionType()) {
> + if (isUnionUninit(FR)) {
> + if (addFieldToUninits({LocalChain, FR}))
> + ContainsUninitField = true;
> + } else
> + IsAnyFieldInitialized = true;
> + continue;
> + }
> +
> + if (T->isArrayType()) {
> + IsAnyFieldInitialized = true;
> + continue;
> + }
> +
> + if (T->isMemberPointerType()) {
> + if (isMemberPointerUninit(FR, LocalChain))
> + ContainsUninitField = true;
> + continue;
> + }
> +
> + // If this is a pointer or reference type.
> + if (T->isPointerType() || T->isReferenceType()) {
> + if (isPointerOrReferenceUninit(FR, LocalChain))
> + ContainsUninitField = true;
> + continue;
> + }
> +
> + assert(isPrimitiveType(T) && "Non-primitive type! "
> + "At this point FR must be primitive!");
> +
> + SVal V = State->getSVal(FieldVal);
> +
> + if (isPrimitiveUninit(V)) {
> + if (addFieldToUninits({LocalChain, FR}))
> + ContainsUninitField = true;
> + }
> + }
> +
> + // Checking bases.
> + // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
> + // is a descendant of another type will emit warnings for uninitalized
> + // inherited members.
> + // This is not the only way to analyze bases of an object -- if we didn't
> + // filter them out, and didn't analyze the bases, this checker would run for
> + // each base of the object in order of base initailization and in theory would
> + // find every uninitalized field. This approach could also make handling
> + // diamond inheritances more easily.
> + //
> + // This rule (that a descendant type's cunstructor is responsible for
> + // initializing inherited data members) is not obvious, and should it should
> + // be.
> + const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
> + if (!CXXRD)
> + return ContainsUninitField;
> +
> + for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
> + const auto *BaseRegion = State->getLValue(BaseSpec, R)
> + .castAs<loc::MemRegionVal>()
> + .getRegionAs<TypedValueRegion>();
> +
> + if (isNonUnionUninit(BaseRegion, LocalChain))
> + ContainsUninitField = true;
> + }
> +
> + return ContainsUninitField;
> +}
> +
> +bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
> + assert(R->getValueType()->isUnionType() &&
> + "This method only checks union objects!");
> + // TODO: Implement support for union fields.
> + return false;
> +}
> +
> +// Note that pointers/references don't contain fields themselves, so in this
> +// function we won't add anything to LocalChain.
> +bool FindUninitializedFields::isPointerOrReferenceUninit(
> + const FieldRegion *FR, FieldChainInfo LocalChain) {
> +
> + assert((FR->getDecl()->getType()->isPointerType() ||
> + FR->getDecl()->getType()->isReferenceType()) &&
> + "This method only checks pointer/reference objects!");
> +
> + SVal V = State->getSVal(FR);
> +
> + if (V.isUnknown() || V.isZeroConstant()) {
> + IsAnyFieldInitialized = true;
> + return false;
> + }
> +
> + if (V.isUndef()) {
> + return addFieldToUninits({LocalChain, FR});
> + }
> +
> + const FieldDecl *FD = FR->getDecl();
> +
> + // TODO: The dynamic type of a void pointer may be retrieved with
> + // `getDynamicTypeInfo`.
> + if (isVoidPointer(FD)) {
> + IsAnyFieldInitialized = true;
> + return false;
> + }
> +
> + assert(V.getAs<Loc>() && "V should be Loc at this point!");
> +
> + // At this point the pointer itself is initialized and points to a valid
> + // location, we'll now check the pointee.
> + SVal DerefdV = State->getSVal(V.castAs<Loc>());
> +
> + // TODO: Dereferencing should be done according to the dynamic type.
> + while (Optional<Loc> L = DerefdV.getAs<Loc>()) {
> + DerefdV = State->getSVal(*L);
> + }
> +
> + // If V is a pointer pointing to a record type.
> + if (Optional<nonloc::LazyCompoundVal> RecordV =
> + DerefdV.getAs<nonloc::LazyCompoundVal>()) {
> +
> + const TypedValueRegion *R = 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 Static Analyzer will construct a symbolic region for Node *next; or
> + // similar code snippets.
> + if (R->getSymbolicBase()) {
> + IsAnyFieldInitialized = true;
> + return false;
> + }
> +
> + const QualType T = R->getValueType();
> +
> + if (T->isStructureOrClassType())
> + return isNonUnionUninit(R, {LocalChain, FR});
> +
> + if (T->isUnionType()) {
> + if (isUnionUninit(R)) {
> + return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
> + } else {
> + IsAnyFieldInitialized = true;
> + return false;
> + }
> + }
> +
> + if (T->isArrayType()) {
> + IsAnyFieldInitialized = true;
> + return false;
> + }
> +
> + llvm_unreachable("All cases are handled!");
> + }
> +
> + // TODO: If possible, it should be asserted that the DerefdV at this point is
> + // primitive.
> +
> + if (isPrimitiveUninit(DerefdV))
> + return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
> +
> + IsAnyFieldInitialized = true;
> + return false;
> +}
> +
> +bool FindUninitializedFields::isMemberPointerUninit(const FieldRegion *FR,
> + FieldChainInfo LocalChain) {
> + assert(FR->getDecl()->getType()->isMemberPointerType() &&
> + "This function only checks regions that hold MemberPointerTypes!");
> + // TODO: Implement support for MemberPointerTypes.
> + return false;
> +}
> +
> +bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
> + if (V.isUndef())
> + return true;
> +
> + IsAnyFieldInitialized = true;
> + return false;
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Methods for FieldChainInfo.
> +//===----------------------------------------------------------------------===//
> +
> +FieldChainInfo::FieldChainInfo(const FieldChainInfo &Other,
> + const FieldRegion *FR, const bool IsDereferenced)
> + : FieldChainInfo(Other, IsDereferenced) {
> + assert(!contains(FR) && "Can't add a field that is already a part of the "
> + "fieldchain! Is this a cyclic reference?");
> + Chain = Factory.add(FR, Other.Chain);
> +}
> +
> +bool FieldChainInfo::isPointer() const {
> + assert(!Chain.isEmpty() && "Empty fieldchain!");
> + return (*Chain.begin())->getDecl()->getType()->isPointerType();
> +}
> +
> +bool FieldChainInfo::isDereferenced() const {
> + assert(isPointer() && "Only pointers may or may not be dereferenced!");
> + return IsDereferenced;
> +}
> +
> +const FieldDecl *FieldChainInfo::getEndOfChain() const {
> + assert(!Chain.isEmpty() && "Empty fieldchain!");
> + return (*Chain.begin())->getDecl();
> +}
> +
> +// TODO: This function constructs an incorrect fieldchain string in the
> +// following case:
> +//
> +// struct Base { int x; };
> +// struct D1 : Base {}; struct D2 : Base {};
> +//
> +// struct MostDerived : D1, D2 {
> +// MostDerived() {}
> +// }
> +//
> +// A call to MostDerived::MostDerived() will cause two notes that say
> +// "uninitialized field 'this->x'", but we can't refer to 'x' directly,
> +// we need an explicit namespace resolution whether the uninit field was
> +// 'D1::x' or 'D2::x'.
> +//
> +// TODO: If a field in the fieldchain is a captured lambda parameter, this
> +// function constructs an empty string for it:
> +//
> +// template <class Callable> struct A {
> +// Callable c;
> +// A(const Callable &c, int) : c(c) {}
> +// };
> +//
> +// int b; // say that this isn't zero initialized
> +// auto alwaysTrue = [&b](int a) { return true; };
> +//
> +// A call with these parameters: A<decltype(alwaysTrue)>::A(alwaysTrue, int())
> +// will emit a note with the message "uninitialized field: 'this->c.'". If
> +// possible, the lambda parameter name should be retrieved or be replaced with a
> +// "<lambda parameter>" or something similar.
> +void FieldChainInfo::print(llvm::raw_ostream &Out) const {
> + if (Chain.isEmpty())
> + return;
> +
> + const llvm::ImmutableListImpl<const FieldRegion *> *L =
> + Chain.getInternalPointer();
> + printTail(Out, L->getTail());
> + Out << L->getHead()->getDecl()->getNameAsString();
> +}
> +
> +void FieldChainInfo::printTail(
> + llvm::raw_ostream &Out,
> + const llvm::ImmutableListImpl<const FieldRegion *> *L) {
> + if (!L)
> + return;
> +
> + printTail(Out, L->getTail());
> + const FieldDecl *Field = L->getHead()->getDecl();
> + Out << Field->getNameAsString();
> + Out << (Field->getType()->isPointerType() ? "->" : ".");
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Utility functions.
> +//===----------------------------------------------------------------------===//
> +
> +namespace {
> +
> +bool isVoidPointer(const FieldDecl *FD) {
> + QualType T = FD->getType();
> +
> + while (!T.isNull()) {
> + if (T->isVoidPointerType())
> + return true;
> + T = T->getPointeeType();
> + }
> + return false;
> +}
> +
> +Optional<nonloc::LazyCompoundVal>
> +getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
> +
> + Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
> + Context.getStackFrame());
> + // Getting the value for 'this'.
> + SVal This = Context.getState()->getSVal(ThisLoc);
> +
> + // Getting the value for '*this'.
> + SVal Object = Context.getState()->getSVal(This.castAs<Loc>());
> +
> + return Object.getAs<nonloc::LazyCompoundVal>();
> +}
> +
> +// TODO: We should also check that if the constructor was called by another
> +// constructor, whether those two are in any relation to one another. In it's
> +// current state, this introduces some false negatives.
> +bool isCalledByConstructor(const CheckerContext &Context) {
> + const LocationContext *LC = Context.getLocationContext()->getParent();
> +
> + while (LC) {
> + if (isa<CXXConstructorDecl>(LC->getDecl()))
> + return true;
> +
> + LC = LC->getParent();
> + }
> + return false;
> +}
> +
> +} // end of anonymous namespace
> +
> +void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
> + auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
> + Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption(
> + "Pedantic", /*DefaultVal*/ false, Chk);
> +}
>
> Added: cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h (added)
> +++ cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h Mon Jun 18 04:50:17 2018
> @@ -0,0 +1,18 @@
> +// Like the compiler, the static analyzer treats some functions differently if
> +// they come from a system header -- for example, it is assumed that system
> +// functions do not arbitrarily free() their parameters, and that some bugs
> +// found in system headers cannot be fixed by the user and should be
> +// suppressed.
> +
> +#pragma clang system_header
> +
> +struct RecordInSystemHeader {
> + int a;
> + int b;
> +};
> +
> +template <class T>
> +struct ContainerInSystemHeader {
> + T &t;
> + ContainerInSystemHeader(T& t) : t(t) {}
> +};
>
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp Mon Jun 18 04:50:17 2018
> @@ -0,0 +1,775 @@
> +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -verify %s
> +
> +//===----------------------------------------------------------------------===//
> +// Non-polymorphic inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +class NonPolymorphicLeft1 {
> + int x;
> +
> +protected:
> + int y;
> +
> +public:
> + NonPolymorphicLeft1() = default;
> + NonPolymorphicLeft1(int) : x(1) {}
> +};
> +
> +class NonPolymorphicInheritanceTest1 : public NonPolymorphicLeft1 {
> + int z;
> +
> +public:
> + NonPolymorphicInheritanceTest1()
> + : NonPolymorphicLeft1(int{}) {
> + y = 2;
> + z = 3;
> + // All good!
> + }
> +};
> +
> +void fNonPolymorphicInheritanceTest1() {
> + NonPolymorphicInheritanceTest1();
> +}
> +
> +class NonPolymorphicBaseClass2 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> +protected:
> + int y;
> +
> +public:
> + NonPolymorphicBaseClass2() = default;
> + NonPolymorphicBaseClass2(int) : x(4) {}
> +};
> +
> +class NonPolymorphicInheritanceTest2 : public NonPolymorphicBaseClass2 {
> + int z;
> +
> +public:
> + NonPolymorphicInheritanceTest2() {
> + y = 5;
> + z = 6; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fNonPolymorphicInheritanceTest2() {
> + NonPolymorphicInheritanceTest2();
> +}
> +
> +class NonPolymorphicBaseClass3 {
> + int x;
> +
> +protected:
> + int y; // expected-note{{uninitialized field 'this->y'}}
> +public:
> + NonPolymorphicBaseClass3() = default;
> + NonPolymorphicBaseClass3(int) : x(7) {}
> +};
> +
> +class NonPolymorphicInheritanceTest3 : public NonPolymorphicBaseClass3 {
> + int z;
> +
> +public:
> + NonPolymorphicInheritanceTest3()
> + : NonPolymorphicBaseClass3(int{}) {
> + z = 8; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fNonPolymorphicInheritanceTest3() {
> + NonPolymorphicInheritanceTest3();
> +}
> +
> +class NonPolymorphicBaseClass4 {
> + int x;
> +
> +protected:
> + int y;
> +
> +public:
> + NonPolymorphicBaseClass4() = default;
> + NonPolymorphicBaseClass4(int) : x(9) {}
> +};
> +
> +class NonPolymorphicInheritanceTest4 : public NonPolymorphicBaseClass4 {
> + int z; // expected-note{{uninitialized field 'this->z'}}
> +
> +public:
> + NonPolymorphicInheritanceTest4()
> + : NonPolymorphicBaseClass4(int{}) {
> + y = 10; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fNonPolymorphicInheritanceTest4() {
> + NonPolymorphicInheritanceTest4();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Polymorphic inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +class PolymorphicLeft1 {
> + int x;
> +
> +protected:
> + int y;
> +
> +public:
> + virtual ~PolymorphicLeft1() = default;
> + PolymorphicLeft1() = default;
> + PolymorphicLeft1(int) : x(11) {}
> +};
> +
> +class PolymorphicInheritanceTest1 : public PolymorphicLeft1 {
> + int z;
> +
> +public:
> + PolymorphicInheritanceTest1()
> + : PolymorphicLeft1(int{}) {
> + y = 12;
> + z = 13;
> + // All good!
> + }
> +};
> +
> +void fPolymorphicInheritanceTest1() {
> + PolymorphicInheritanceTest1();
> +}
> +
> +class PolymorphicRight1 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> +protected:
> + int y;
> +
> +public:
> + virtual ~PolymorphicRight1() = default;
> + PolymorphicRight1() = default;
> + PolymorphicRight1(int) : x(14) {}
> +};
> +
> +class PolymorphicInheritanceTest2 : public PolymorphicRight1 {
> + int z;
> +
> +public:
> + PolymorphicInheritanceTest2() {
> + y = 15;
> + z = 16; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fPolymorphicInheritanceTest2() {
> + PolymorphicInheritanceTest2();
> +}
> +
> +class PolymorphicBaseClass3 {
> + int x;
> +
> +protected:
> + int y; // expected-note{{uninitialized field 'this->y'}}
> +public:
> + virtual ~PolymorphicBaseClass3() = default;
> + PolymorphicBaseClass3() = default;
> + PolymorphicBaseClass3(int) : x(17) {}
> +};
> +
> +class PolymorphicInheritanceTest3 : public PolymorphicBaseClass3 {
> + int z;
> +
> +public:
> + PolymorphicInheritanceTest3()
> + : PolymorphicBaseClass3(int{}) {
> + z = 18; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fPolymorphicInheritanceTest3() {
> + PolymorphicInheritanceTest3();
> +}
> +
> +class PolymorphicBaseClass4 {
> + int x;
> +
> +protected:
> + int y;
> +
> +public:
> + virtual ~PolymorphicBaseClass4() = default;
> + PolymorphicBaseClass4() = default;
> + PolymorphicBaseClass4(int) : x(19) {}
> +};
> +
> +class PolymorphicInheritanceTest4 : public PolymorphicBaseClass4 {
> + int z; // expected-note{{uninitialized field 'this->z'}}
> +
> +public:
> + PolymorphicInheritanceTest4()
> + : PolymorphicBaseClass4(int{}) {
> + y = 20; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fPolymorphicInheritanceTest4() {
> + PolymorphicInheritanceTest4();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Virtual inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +class VirtualPolymorphicLeft1 {
> + int x;
> +
> +protected:
> + int y;
> +
> +public:
> + virtual ~VirtualPolymorphicLeft1() = default;
> + VirtualPolymorphicLeft1() = default;
> + VirtualPolymorphicLeft1(int) : x(21) {}
> +};
> +
> +class VirtualInheritanceTest1 : virtual public VirtualPolymorphicLeft1 {
> + int z;
> +
> +public:
> + VirtualInheritanceTest1()
> + : VirtualPolymorphicLeft1(int()) {
> + y = 22;
> + z = 23;
> + // All good!
> + }
> +};
> +
> +void fVirtualInheritanceTest1() {
> + VirtualInheritanceTest1();
> +}
> +
> +class VirtualPolymorphicRight1 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> +protected:
> + int y;
> +
> +public:
> + virtual ~VirtualPolymorphicRight1() = default;
> + VirtualPolymorphicRight1() = default;
> + VirtualPolymorphicRight1(int) : x(24) {}
> +};
> +
> +class VirtualInheritanceTest2 : virtual public VirtualPolymorphicRight1 {
> + int z;
> +
> +public:
> + VirtualInheritanceTest2() {
> + y = 25;
> + z = 26; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fVirtualInheritanceTest2() {
> + VirtualInheritanceTest2();
> +}
> +
> +class VirtualPolymorphicBaseClass3 {
> + int x;
> +
> +protected:
> + int y; // expected-note{{uninitialized field 'this->y'}}
> +public:
> + virtual ~VirtualPolymorphicBaseClass3() = default;
> + VirtualPolymorphicBaseClass3() = default;
> + VirtualPolymorphicBaseClass3(int) : x(27) {}
> +};
> +
> +class VirtualInheritanceTest3 : virtual public VirtualPolymorphicBaseClass3 {
> + int z;
> +
> +public:
> + VirtualInheritanceTest3()
> + : VirtualPolymorphicBaseClass3(int{}) {
> + z = 28; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fVirtualInheritanceTest3() {
> + VirtualInheritanceTest3();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Multiple inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +/*
> + Left Right
> + \ /
> + \ /
> + \ /
> + MultipleInheritanceTest
> +*/
> +
> +struct Left1 {
> + int x;
> + Left1() = default;
> + Left1(int) : x(29) {}
> +};
> +struct Right1 {
> + int y;
> + Right1() = default;
> + Right1(int) : y(30) {}
> +};
> +
> +class MultipleInheritanceTest1 : public Left1, public Right1 {
> + int z;
> +
> +public:
> + MultipleInheritanceTest1()
> + : Left1(int{}),
> + Right1(char{}) {
> + z = 31;
> + // All good!
> + }
> +
> + MultipleInheritanceTest1(int)
> + : Left1(int{}) {
> + y = 32;
> + z = 33;
> + // All good!
> + }
> +
> + MultipleInheritanceTest1(int, int)
> + : Right1(char{}) {
> + x = 34;
> + z = 35;
> + // All good!
> + }
> +};
> +
> +void fMultipleInheritanceTest1() {
> + MultipleInheritanceTest1();
> + MultipleInheritanceTest1(int());
> + MultipleInheritanceTest1(int(), int());
> +}
> +
> +struct Left2 {
> + int x;
> + Left2() = default;
> + Left2(int) : x(36) {}
> +};
> +struct Right2 {
> + int y; // expected-note{{uninitialized field 'this->y'}}
> + Right2() = default;
> + Right2(int) : y(37) {}
> +};
> +
> +class MultipleInheritanceTest2 : public Left2, public Right2 {
> + int z;
> +
> +public:
> + MultipleInheritanceTest2()
> + : Left2(int{}) {
> + z = 38; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fMultipleInheritanceTest2() {
> + MultipleInheritanceTest2();
> +}
> +
> +struct Left3 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + Left3() = default;
> + Left3(int) : x(39) {}
> +};
> +struct Right3 {
> + int y;
> + Right3() = default;
> + Right3(int) : y(40) {}
> +};
> +
> +class MultipleInheritanceTest3 : public Left3, public Right3 {
> + int z;
> +
> +public:
> + MultipleInheritanceTest3()
> + : Right3(char{}) {
> + z = 41; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fMultipleInheritanceTest3() {
> + MultipleInheritanceTest3();
> +}
> +
> +struct Left4 {
> + int x;
> + Left4() = default;
> + Left4(int) : x(42) {}
> +};
> +struct Right4 {
> + int y;
> + Right4() = default;
> + Right4(int) : y(43) {}
> +};
> +
> +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 fMultipleInheritanceTest4() {
> + MultipleInheritanceTest4();
> +}
> +
> +struct Left5 {
> + int x;
> + Left5() = default;
> + Left5(int) : x(44) {}
> +};
> +struct Right5 {
> + int y; // expected-note{{uninitialized field 'this->y'}}
> + Right5() = default;
> + Right5(int) : y(45) {}
> +};
> +
> +class MultipleInheritanceTest5 : public Left5, public Right5 {
> + int z; // expected-note{{uninitialized field 'this->z'}}
> +
> +public:
> + MultipleInheritanceTest5() // expected-warning{{2 uninitialized fields}}
> + : Left5(int{}) {
> + }
> +};
> +
> +void fMultipleInheritanceTest5() {
> + MultipleInheritanceTest5();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Non-virtual diamond inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +/*
> + NonVirtualBase NonVirtualBase
> + | |
> + | |
> + | |
> + First Second
> + \ /
> + \ /
> + \ /
> + NonVirtualDiamondInheritanceTest
> +*/
> +
> +struct NonVirtualBase1 {
> + int x;
> + NonVirtualBase1() = default;
> + NonVirtualBase1(int) : x(46) {}
> +};
> +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 = 47;
> + // All good!
> + }
> +
> + NonVirtualDiamondInheritanceTest1(int)
> + : First1(int{}) {
> + Second1::x = 48;
> + z = 49;
> + // All good!
> + }
> +
> + NonVirtualDiamondInheritanceTest1(int, int)
> + : Second1(int{}) {
> + First1::x = 50;
> + z = 51;
> + // All good!
> + }
> +};
> +
> +void fNonVirtualDiamondInheritanceTest1() {
> + NonVirtualDiamondInheritanceTest1();
> + NonVirtualDiamondInheritanceTest1(int());
> + NonVirtualDiamondInheritanceTest1(int(), int());
> +}
> +
> +struct NonVirtualBase2 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + NonVirtualBase2() = default;
> + NonVirtualBase2(int) : x(52) {}
> +};
> +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 = 53; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fNonVirtualDiamondInheritanceTest2() {
> + NonVirtualDiamondInheritanceTest2();
> +}
> +
> +struct NonVirtualBase3 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + NonVirtualBase3() = default;
> + NonVirtualBase3(int) : x(54) {}
> +};
> +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 = 55; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fNonVirtualDiamondInheritanceTest3() {
> + NonVirtualDiamondInheritanceTest3();
> +}
> +
> +struct NonVirtualBase4 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + // expected-note at -1{{uninitialized field 'this->x'}}
> + NonVirtualBase4() = default;
> + NonVirtualBase4(int) : x(56) {}
> +};
> +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 = 57; // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fNonVirtualDiamondInheritanceTest4() {
> + NonVirtualDiamondInheritanceTest4();
> +}
> +
> +struct NonVirtualBase5 {
> + int x;
> + NonVirtualBase5() = default;
> + NonVirtualBase5(int) : x(58) {}
> +};
> +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 fNonVirtualDiamondInheritanceTest5() {
> + NonVirtualDiamondInheritanceTest5();
> +}
> +
> +struct NonVirtualBase6 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + NonVirtualBase6() = default;
> + NonVirtualBase6(int) : x(59) {}
> +};
> +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 fNonVirtualDiamondInheritanceTest6() {
> + NonVirtualDiamondInheritanceTest6();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Virtual diamond inheritance tests
> +//===----------------------------------------------------------------------===//
> +
> +/*
> + VirtualBase
> + / \
> + / \
> + / \
> + VirtualFirst VirtualSecond
> + \ /
> + \ /
> + \ /
> + VirtualDiamondInheritanceTest
> +*/
> +
> +struct VirtualBase1 {
> + int x;
> + VirtualBase1() = default;
> + VirtualBase1(int) : x(60) {}
> +};
> +struct VirtualFirst1 : virtual public VirtualBase1 {
> + VirtualFirst1() = default;
> + VirtualFirst1(int) : VirtualBase1(int{}) {}
> + VirtualFirst1(int, int) { x = 61; }
> +};
> +struct VirtualSecond1 : virtual public VirtualBase1 {
> + VirtualSecond1() = default;
> + VirtualSecond1(int) : VirtualBase1(int{}) {}
> + VirtualSecond1(int, int) { x = 62; }
> +};
> +
> +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 fVirtualDiamondInheritanceTest1() {
> + VirtualDiamondInheritanceTest1();
> + VirtualDiamondInheritanceTest1(int());
> + VirtualDiamondInheritanceTest1(int(), int());
> +}
> +
> +struct VirtualBase2 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + VirtualBase2() = default;
> + VirtualBase2(int) : x(63) {}
> +};
> +struct VirtualFirst2 : virtual public VirtualBase2 {
> + VirtualFirst2() = default;
> + VirtualFirst2(int) : VirtualBase2(int{}) {}
> + VirtualFirst2(int, int) { x = 64; }
> +};
> +struct VirtualSecond2 : virtual public VirtualBase2 {
> + VirtualSecond2() = default;
> + VirtualSecond2(int) : VirtualBase2(int{}) {}
> + VirtualSecond2(int, int) { x = 65; }
> +};
> +
> +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 fVirtualDiamondInheritanceTest2() {
> + VirtualDiamondInheritanceTest2();
> +}
> +
> +struct VirtualBase3 {
> + int x; // expected-note{{uninitialized field 'this->x'}}
> + VirtualBase3() = default;
> + VirtualBase3(int) : x(66) {}
> +};
> +struct VirtualFirst3 : virtual public VirtualBase3 {
> + VirtualFirst3() = default;
> + VirtualFirst3(int) : VirtualBase3(int{}) {}
> + VirtualFirst3(int, int) { x = 67; }
> +};
> +struct VirtualSecond3 : virtual public VirtualBase3 {
> + VirtualSecond3() = default;
> + VirtualSecond3(int) : VirtualBase3(int{}) {}
> + VirtualSecond3(int, int) { x = 68; }
> +};
> +
> +class VirtualDiamondInheritanceTest3 : public VirtualFirst3, public VirtualSecond3 {
> +
> +public:
> + VirtualDiamondInheritanceTest3() // expected-warning{{1 uninitialized field}}
> + : VirtualFirst3(int{}) {}
> +};
> +
> +void fVirtualDiamondInheritanceTest3() {
> + VirtualDiamondInheritanceTest3();
> +}
>
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Mon Jun 18 04:50:17 2018
> @@ -0,0 +1,699 @@
> +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
> +
> +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
> +
> +//===----------------------------------------------------------------------===//
> +// Concrete location tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct ConcreteIntLocTest {
> + int *ptr;
> +
> + ConcreteIntLocTest() : ptr(reinterpret_cast<int *>(0xDEADBEEF)) {}
> +};
> +
> +void fConcreteIntLocTest() {
> + ConcreteIntLocTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Null pointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +class NullPtrTest {
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> + float *fptr = nullptr;
> + int *ptr;
> + RecordType *recPtr;
> +
> +public:
> + NullPtrTest() : ptr(nullptr), recPtr(nullptr) {
> + // All good!
> + }
> +};
> +
> +void fNullPtrTest() {
> + NullPtrTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Heap pointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +class HeapPointerTest1 {
> + struct RecordType {
> + // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}}
> + int x; // no-note
> + // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}}
> + int y; // no-note
> + };
> + // TODO: we'd expect the note: {{uninitialized pointee 'this->fptr'}}
> + float *fptr = new float; // no-note
> + // TODO: we'd expect the note: {{uninitialized pointee 'this->ptr'}}
> + int *ptr; // no-note
> + RecordType *recPtr;
> +
> +public:
> + // TODO: we'd expect the warning: {{4 uninitialized fields}}
> + HeapPointerTest1() : ptr(new int), recPtr(new RecordType) { // no-note
> + }
> +};
> +
> +void fHeapPointerTest1() {
> + 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{25}), recPtr(new RecordType{26, 27}) {
> + // All good!
> + }
> +};
> +
> +void fHeapPointerTest2() {
> + HeapPointerTest2();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Stack pointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +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 fStackPointerTest1() {
> + int ok_a = 28;
> + StackPointerTest1::RecordType ok_rec{29, 30};
> + StackPointerTest1(&ok_a, &ok_rec); // 'a', 'rec.x', 'rec.y' uninitialized
> +}
> +
> +#ifdef PEDANTIC
> +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 fStackPointerTest2() {
> + int a;
> + StackPointerTest2::RecordType rec;
> + StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized
> +}
> +#else
> +class StackPointerTest2 {
> +public:
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> +private:
> + int *ptr;
> + RecordType *recPtr;
> +
> +public:
> + StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) {
> + }
> +};
> +
> +void fStackPointerTest2() {
> + int a;
> + StackPointerTest2::RecordType rec;
> + StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized
> +}
> +#endif // PEDANTIC
> +
> +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 fUninitPointerTest() {
> + UninitPointerTest();
> +}
> +
> +struct CharPointerTest {
> + const char *str;
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + CharPointerTest() : str("") {}
> +};
> +
> +void fCharPointerTest() {
> + CharPointerTest();
> +}
> +
> +struct CyclicPointerTest {
> + int *ptr;
> + CyclicPointerTest() : ptr(reinterpret_cast<int*>(&ptr)) {}
> +};
> +
> +void fCyclicPointerTest() {
> + CyclicPointerTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Void pointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +// Void pointer tests are mainly no-crash tests.
> +
> +void *malloc(int size);
> +
> +class VoidPointerTest1 {
> + void *vptr;
> +
> +public:
> + VoidPointerTest1(void *vptr, char) : vptr(vptr) {
> + // All good!
> + }
> +};
> +
> +void fVoidPointerTest1() {
> + void *vptr = malloc(sizeof(int));
> + VoidPointerTest1(vptr, char());
> +}
> +
> +class VoidPointerTest2 {
> + void **vpptr;
> +
> +public:
> + VoidPointerTest2(void **vpptr, char) : vpptr(vpptr) {
> + // All good!
> + }
> +};
> +
> +void fVoidPointerTest2() {
> + void *vptr = malloc(sizeof(int));
> + VoidPointerTest2(&vptr, char());
> +}
> +
> +class VoidPointerRRefTest1 {
> + void *&&vptrrref;
> +
> +public:
> + VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) {
> + // All good!
> + }
> +};
> +
> +void fVoidPointerRRefTest1() {
> + void *vptr = malloc(sizeof(int));
> + VoidPointerRRefTest1(vptr, char());
> +}
> +
> +class VoidPointerRRefTest2 {
> + void **&&vpptrrref;
> +
> +public:
> + VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) {
> + // All good!
> + }
> +};
> +
> +void fVoidPointerRRefTest2() {
> + void *vptr = malloc(sizeof(int));
> + VoidPointerRRefTest2(&vptr, char());
> +}
> +
> +class VoidPointerLRefTest {
> + void *&vptrrref;
> +
> +public:
> + VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) {
> + // All good!
> + }
> +};
> +
> +void fVoidPointerLRefTest() {
> + void *vptr = malloc(sizeof(int));
> + VoidPointerLRefTest(vptr, char());
> +}
> +
> +struct CyclicVoidPointerTest {
> + void *vptr; // no-crash
> +
> + CyclicVoidPointerTest() : vptr(&vptr) {}
> +
> +};
> +
> +void fCyclicVoidPointerTest() {
> + CyclicVoidPointerTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Multipointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +#ifdef PEDANTIC
> +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 fMultiPointerTest1() {
> + MultiPointerTest1::RecordType *p1;
> + MultiPointerTest1::RecordType **mptr = &p1;
> + MultiPointerTest1(mptr, int()); // '*mptr' uninitialized
> +}
> +#else
> +class MultiPointerTest1 {
> +public:
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> +private:
> + RecordType **mptr;
> +
> +public:
> + MultiPointerTest1(RecordType **p, int) : mptr(p) {}
> +};
> +
> +void fMultiPointerTest1() {
> + MultiPointerTest1::RecordType *p1;
> + MultiPointerTest1::RecordType **mptr = &p1;
> + MultiPointerTest1(mptr, int()); // '*mptr' uninitialized
> +}
> +#endif // PEDANTIC
> +
> +#ifdef PEDANTIC
> +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 fMultiPointerTest2() {
> + MultiPointerTest2::RecordType i;
> + MultiPointerTest2::RecordType *p1 = &i;
> + MultiPointerTest2::RecordType **mptr = &p1;
> + MultiPointerTest2(mptr, int()); // '**mptr' uninitialized
> +}
> +#else
> +class MultiPointerTest2 {
> +public:
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> +private:
> + RecordType **mptr;
> +
> +public:
> + MultiPointerTest2(RecordType **p, int) : mptr(p) {
> + }
> +};
> +
> +void fMultiPointerTest2() {
> + MultiPointerTest2::RecordType i;
> + MultiPointerTest2::RecordType *p1 = &i;
> + MultiPointerTest2::RecordType **mptr = &p1;
> + MultiPointerTest2(mptr, int()); // '**mptr' uninitialized
> +}
> +#endif // PEDANTIC
> +
> +class MultiPointerTest3 {
> +public:
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> +private:
> + RecordType **mptr;
> +
> +public:
> + MultiPointerTest3(RecordType **p, int) : mptr(p) {
> + // All good!
> + }
> +};
> +
> +void fMultiPointerTest3() {
> + MultiPointerTest3::RecordType i{31, 32};
> + MultiPointerTest3::RecordType *p1 = &i;
> + MultiPointerTest3::RecordType **mptr = &p1;
> + MultiPointerTest3(mptr, int()); // '**mptr' uninitialized
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Member pointer tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct UsefulFunctions {
> + int a, b;
> +
> + void print() {}
> + void dump() {}
> +};
> +
> +#ifdef PEDANTIC
> +struct PointerToMemberFunctionTest1 {
> + // TODO: we'd expect the note {{uninitialized field 'this->f'}}
> + void (UsefulFunctions::*f)(void); // no-note
> + PointerToMemberFunctionTest1() {}
> +};
> +
> +void fPointerToMemberFunctionTest1() {
> + // TODO: we'd expect the warning {{1 uninitialized field}}
> + PointerToMemberFunctionTest1(); // no-warning
> +}
> +
> +struct PointerToMemberFunctionTest2 {
> + void (UsefulFunctions::*f)(void);
> + PointerToMemberFunctionTest2(void (UsefulFunctions::*f)(void)) : f(f) {
> + // All good!
> + }
> +};
> +
> +void fPointerToMemberFunctionTest2() {
> + void (UsefulFunctions::*f)(void) = &UsefulFunctions::print;
> + PointerToMemberFunctionTest2 a(f);
> +}
> +
> +struct MultiPointerToMemberFunctionTest1 {
> + void (UsefulFunctions::**f)(void); // expected-note{{uninitialized pointer 'this->f'}}
> + MultiPointerToMemberFunctionTest1() {}
> +};
> +
> +void fMultiPointerToMemberFunctionTest1() {
> + MultiPointerToMemberFunctionTest1(); // expected-warning{{1 uninitialized field}}
> +}
> +
> +struct MultiPointerToMemberFunctionTest2 {
> + void (UsefulFunctions::**f)(void);
> + MultiPointerToMemberFunctionTest2(void (UsefulFunctions::**f)(void)) : f(f) {
> + // All good!
> + }
> +};
> +
> +void fMultiPointerToMemberFunctionTest2() {
> + void (UsefulFunctions::*f)(void) = &UsefulFunctions::print;
> + MultiPointerToMemberFunctionTest2 a(&f);
> +}
> +
> +struct PointerToMemberDataTest1 {
> + // TODO: we'd expect the note {{uninitialized field 'this->f'}}
> + int UsefulFunctions::*d; // no-note
> + PointerToMemberDataTest1() {}
> +};
> +
> +void fPointerToMemberDataTest1() {
> + // TODO: we'd expect the warning {{1 uninitialized field}}
> + PointerToMemberDataTest1(); // no-warning
> +}
> +
> +struct PointerToMemberDataTest2 {
> + int UsefulFunctions::*d;
> + PointerToMemberDataTest2(int UsefulFunctions::*d) : d(d) {
> + // All good!
> + }
> +};
> +
> +void fPointerToMemberDataTest2() {
> + int UsefulFunctions::*d = &UsefulFunctions::a;
> + PointerToMemberDataTest2 a(d);
> +}
> +
> +struct MultiPointerToMemberDataTest1 {
> + int UsefulFunctions::**d; // expected-note{{uninitialized pointer 'this->d'}}
> + MultiPointerToMemberDataTest1() {}
> +};
> +
> +void fMultiPointerToMemberDataTest1() {
> + MultiPointerToMemberDataTest1(); // expected-warning{{1 uninitialized field}}
> +}
> +
> +struct MultiPointerToMemberDataTest2 {
> + int UsefulFunctions::**d;
> + MultiPointerToMemberDataTest2(int UsefulFunctions::**d) : d(d) {
> + // All good!
> + }
> +};
> +
> +void fMultiPointerToMemberDataTest2() {
> + int UsefulFunctions::*d = &UsefulFunctions::a;
> + MultiPointerToMemberDataTest2 a(&d);
> +}
> +#endif // PEDANTIC
> +
> +//===----------------------------------------------------------------------===//
> +// Tests for list-like records.
> +//===----------------------------------------------------------------------===//
> +
> +class ListTest1 {
> +public:
> + struct Node {
> + Node *next = nullptr; // no crash
> + int i;
> + };
> +
> +private:
> + Node *head = nullptr;
> +
> +public:
> + ListTest1() {
> + // All good!
> + }
> +};
> +
> +void fListTest1() {
> + 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 fListTest2() {
> + ListTest2::Node n;
> + ListTest2(&n, int());
> +}
> +
> +class CyclicList {
> +public:
> + struct Node {
> + Node *next = nullptr;
> + int i; // expected-note{{uninitialized field 'this->head->i'}}
> + };
> +
> +private:
> + Node *head = nullptr;
> +
> +public:
> + CyclicList(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fCyclicList() {
> + /*
> + n3
> + / \
> + this -- n1 -- n2
> + */
> +
> + CyclicList::Node n1;
> + CyclicList::Node n2;
> + n2.next = &n1;
> + n2.i = 50;
> + CyclicList::Node n3;
> + n3.next = &n2;
> + n3.i = 50;
> + n1.next = &n3;
> + // note that n1.i is uninitialized
> + CyclicList(&n1, 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<RecordType &&>(rref)) {
> + // All good!
> + }
> +};
> +
> +void fReferenceTest1() {
> + ReferenceTest1::RecordType d{33, 34};
> + ReferenceTest1(d, d);
> +}
> +
> +#ifdef PEDANTIC
> +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<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fReferenceTest2() {
> + ReferenceTest2::RecordType c;
> + ReferenceTest2(c, c);
> +}
> +#else
> +class ReferenceTest2 {
> +public:
> + struct RecordType {
> + int x;
> + int y;
> + };
> +
> +private:
> + RecordType &lref;
> + RecordType &&rref;
> +
> +public:
> + ReferenceTest2(RecordType &lref, RecordType &rref)
> + : lref(lref), rref(static_cast<RecordType &&>(rref)) {
> + }
> +};
> +
> +void fReferenceTest2() {
> + ReferenceTest2::RecordType c;
> + ReferenceTest2(c, c);
> +}
> +#endif // PEDANTIC
> +
> +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<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fReferenceTest3() {
> + ReferenceTest3::RecordType c, d{35, 36};
> + 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<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fReferenceTest5() {
> + ReferenceTest4::RecordType c, d{37, 38};
> + ReferenceTest4(d, c);
> +}
>
> Added: cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp?rev=334935&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp (added)
> +++ cfe/trunk/test/Analysis/cxx-uninitialized-object.cpp Mon Jun 18 04:50:17 2018
> @@ -0,0 +1,1058 @@
> +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
> +
> +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
> +
> +//===----------------------------------------------------------------------===//
> +// Default constructor test.
> +//===----------------------------------------------------------------------===//
> +
> +class CompilerGeneratedConstructorTest {
> + int a, b, c, d, e, f, g, h, i, j;
> +
> +public:
> + CompilerGeneratedConstructorTest() = default;
> +};
> +
> +void fCompilerGeneratedConstructorTest() {
> + CompilerGeneratedConstructorTest();
> +}
> +
> +#ifdef PEDANTIC
> +class DefaultConstructorTest {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> +
> +public:
> + DefaultConstructorTest();
> +};
> +
> +DefaultConstructorTest::DefaultConstructorTest() = default;
> +
> +void fDefaultConstructorTest() {
> + DefaultConstructorTest(); // expected-warning{{1 uninitialized field}}
> +}
> +#else
> +class DefaultConstructorTest {
> + int a;
> +
> +public:
> + DefaultConstructorTest();
> +};
> +
> +DefaultConstructorTest::DefaultConstructorTest() = default;
> +
> +void fDefaultConstructorTest() {
> + DefaultConstructorTest();
> +}
> +#endif // PEDANTIC
> +
> +//===----------------------------------------------------------------------===//
> +// Initializer list test.
> +//===----------------------------------------------------------------------===//
> +
> +class InitListTest1 {
> + int a;
> + int b;
> +
> +public:
> + InitListTest1()
> + : a(1),
> + b(2) {
> + // All good!
> + }
> +};
> +
> +void fInitListTest1() {
> + InitListTest1();
> +}
> +
> +class InitListTest2 {
> + int a;
> + int b; // expected-note{{uninitialized field 'this->b'}}
> +
> +public:
> + InitListTest2()
> + : a(3) {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fInitListTest2() {
> + InitListTest2();
> +}
> +
> +class InitListTest3 {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> + int b;
> +
> +public:
> + InitListTest3()
> + : b(4) {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fInitListTest3() {
> + InitListTest3();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Constructor body test.
> +//===----------------------------------------------------------------------===//
> +
> +class CtorBodyTest1 {
> + int a, b;
> +
> +public:
> + CtorBodyTest1() {
> + a = 5;
> + b = 6;
> + // All good!
> + }
> +};
> +
> +void fCtorBodyTest1() {
> + CtorBodyTest1();
> +}
> +
> +class CtorBodyTest2 {
> + int a;
> + int b; // expected-note{{uninitialized field 'this->b'}}
> +
> +public:
> + CtorBodyTest2() {
> + a = 7; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fCtorBodyTest2() {
> + CtorBodyTest2();
> +}
> +
> +class CtorBodyTest3 {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> + int b;
> +
> +public:
> + CtorBodyTest3() {
> + b = 8; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fCtorBodyTest3() {
> + CtorBodyTest3();
> +}
> +
> +#ifdef PEDANTIC
> +class CtorBodyTest4 {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> + int b; // expected-note{{uninitialized field 'this->b'}}
> +
> +public:
> + CtorBodyTest4() {}
> +};
> +
> +void fCtorBodyTest4() {
> + CtorBodyTest4(); // expected-warning{{2 uninitialized fields}}
> +}
> +#else
> +class CtorBodyTest4 {
> + int a;
> + int b;
> +
> +public:
> + CtorBodyTest4() {}
> +};
> +
> +void fCtorBodyTest4() {
> + CtorBodyTest4();
> +}
> +#endif
> +
> +//===----------------------------------------------------------------------===//
> +// Constructor delegation test.
> +//===----------------------------------------------------------------------===//
> +
> +class CtorDelegationTest1 {
> + int a;
> + int b;
> +
> +public:
> + CtorDelegationTest1(int)
> + : a(9) {
> + // leaves 'b' unintialized, but we'll never check this function
> + }
> +
> + CtorDelegationTest1()
> + : CtorDelegationTest1(int{}) { // Initializing 'a'
> + b = 10;
> + // All good!
> + }
> +};
> +
> +void fCtorDelegationTest1() {
> + CtorDelegationTest1();
> +}
> +
> +class CtorDelegationTest2 {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> + int b;
> +
> +public:
> + CtorDelegationTest2(int)
> + : b(11) {
> + // leaves 'a' unintialized, but we'll never check this function
> + }
> +
> + CtorDelegationTest2()
> + : CtorDelegationTest2(int{}) { // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fCtorDelegationTest2() {
> + CtorDelegationTest2();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Tests for classes containing records.
> +//===----------------------------------------------------------------------===//
> +
> +class ContainsRecordTest1 {
> + struct RecordType {
> + int x;
> + int y;
> + } rec;
> + int c, d;
> +
> +public:
> + ContainsRecordTest1()
> + : rec({12, 13}),
> + c(14),
> + d(15) {
> + // All good!
> + }
> +};
> +
> +void fContainsRecordTest1() {
> + ContainsRecordTest1();
> +}
> +
> +class ContainsRecordTest2 {
> + struct RecordType {
> + int x;
> + int y; // expected-note{{uninitialized field 'this->rec.y'}}
> + } rec;
> + int c, d;
> +
> +public:
> + ContainsRecordTest2()
> + : c(16),
> + d(17) {
> + rec.x = 18; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fContainsRecordTest2() {
> + 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(19),
> + d(20) { // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fContainsRecordTest3() {
> + ContainsRecordTest3();
> +}
> +
> +class ContainsRecordTest4 {
> + struct RecordType {
> + int x; // expected-note{{uninitialized field 'this->rec.x'}}
> + int y; // expected-note{{uninitialized field 'this->rec.y'}}
> + } rec;
> + int c, d; // expected-note{{uninitialized field 'this->d'}}
> +
> +public:
> + ContainsRecordTest4()
> + : c(19) { // expected-warning{{3 uninitialized fields}}
> + }
> +};
> +
> +void fContainsRecordTest4() {
> + ContainsRecordTest4();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Tests for template classes.
> +//===----------------------------------------------------------------------===//
> +
> +template <class T>
> +class IntTemplateClassTest1 {
> + T t;
> + int b;
> +
> +public:
> + IntTemplateClassTest1(T i) {
> + b = 21;
> + t = i;
> + // All good!
> + }
> +};
> +
> +void fIntTemplateClassTest1() {
> + IntTemplateClassTest1<int>(22);
> +}
> +
> +template <class T>
> +class IntTemplateClassTest2 {
> + T t; // expected-note{{uninitialized field 'this->t'}}
> + int b;
> +
> +public:
> + IntTemplateClassTest2() {
> + b = 23; // expected-warning{{1 uninitialized field}}
> + }
> +};
> +
> +void fIntTemplateClassTest2() {
> + IntTemplateClassTest2<int>();
> +}
> +
> +struct Record {
> + int x; // expected-note{{uninitialized field 'this->t.x'}}
> + int y; // expected-note{{uninitialized field 'this->t.y'}}
> +};
> +
> +template <class T>
> +class RecordTemplateClassTest {
> + T t;
> + int b;
> +
> +public:
> + RecordTemplateClassTest() {
> + b = 24; // expected-warning{{2 uninitialized fields}}
> + }
> +};
> +
> +void fRecordTemplateClassTest() {
> + RecordTemplateClassTest<Record>();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Tests involving functions with unknown implementations.
> +//===----------------------------------------------------------------------===//
> +
> +template <class T>
> +void mayInitialize(T &);
> +
> +template <class T>
> +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 fPassingToUnknownFunctionTest1() {
> + 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 fPassingToUnknownFunctionTest2() {
> + PassingToUnknownFunctionTest2();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Tests for classes containing unions.
> +//===----------------------------------------------------------------------===//
> +
> +// FIXME: As of writing this checker, there is no good support for union types
> +// in the Static Analyzer. 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/2017-March/052910.html
> +
> +class ContainsSimpleUnionTest1 {
> + union SimpleUnion {
> + float uf;
> + int ui;
> + char uc;
> + } u;
> +
> +public:
> + ContainsSimpleUnionTest1() {
> + u.uf = 3.14;
> + // All good!
> + }
> +};
> +
> +void fContainsSimpleUnionTest1() {
> + ContainsSimpleUnionTest1();
> +}
> +
> +class ContainsSimpleUnionTest2 {
> + union SimpleUnion {
> + float uf;
> + int ui;
> + char uc;
> + // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
> + } u; // no-note
> +
> +public:
> + ContainsSimpleUnionTest2() {}
> +};
> +
> +void fContainsSimpleUnionTest2() {
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + ContainsSimpleUnionTest2(); // no-warning
> +}
> +
> +class UnionPointerTest1 {
> +public:
> + union SimpleUnion {
> + float uf;
> + int ui;
> + char uc;
> + };
> +
> +private:
> + SimpleUnion *uptr;
> +
> +public:
> + UnionPointerTest1(SimpleUnion *uptr, int) : uptr(uptr) {
> + // All good!
> + }
> +};
> +
> +void fUnionPointerTest1() {
> + UnionPointerTest1::SimpleUnion u;
> + u.uf = 41;
> + UnionPointerTest1(&u, int());
> +}
> +
> +class UnionPointerTest2 {
> +public:
> + union SimpleUnion {
> + float uf;
> + int ui;
> + char uc;
> + };
> +
> +private:
> + // TODO: we'd expect the note: {{uninitialized field 'this->uptr'}}
> + SimpleUnion *uptr; // no-note
> +
> +public:
> + UnionPointerTest2(SimpleUnion *uptr, char) : uptr(uptr) {}
> +};
> +
> +void fUnionPointerTest2() {
> + UnionPointerTest2::SimpleUnion u;
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + UnionPointerTest2(&u, int()); // no-warning
> +}
> +
> +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 fContainsUnionWithRecordTest1() {
> + ContainsUnionWithRecordTest1();
> +}
> +
> +class ContainsUnionWithRecordTest2 {
> + union UnionWithRecord {
> + struct RecordType {
> + int x;
> + int y;
> + } us;
> + double ud;
> + long ul;
> +
> + UnionWithRecord(){};
> + } u;
> +
> +public:
> + ContainsUnionWithRecordTest2() {
> + u.us = UnionWithRecord::RecordType{42, 43};
> + // All good!
> + }
> +};
> +
> +void fContainsUnionWithRecordTest2() {
> + ContainsUnionWithRecordTest1();
> +}
> +
> +class ContainsUnionWithRecordTest3 {
> + union UnionWithRecord {
> + struct RecordType {
> + int x;
> + int y;
> + } us;
> + double ud;
> + long ul;
> +
> + UnionWithRecord(){};
> + // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
> + } u; // no-note
> +
> +public:
> + ContainsUnionWithRecordTest3() {
> + UnionWithRecord::RecordType rec;
> + rec.x = 44;
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + u.us = rec; // no-warning
> + }
> +};
> +
> +void fContainsUnionWithRecordTest3() {
> + 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 fContainsUnionWithSimpleUnionTest1() {
> + ContainsUnionWithSimpleUnionTest1();
> +}
> +
> +class ContainsUnionWithSimpleUnionTest2 {
> + union UnionWithSimpleUnion {
> + union SimpleUnion {
> + float uf;
> + int ui;
> + char uc;
> + } usu;
> + long ul;
> + unsigned uu;
> + // TODO: we'd expect the note: {{uninitialized field 'this->u'}}
> + } u; // no-note
> +
> +public:
> + ContainsUnionWithSimpleUnionTest2() {}
> +};
> +
> +void fContainsUnionWithSimpleUnionTest2() {
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + ContainsUnionWithSimpleUnionTest2(); // no-warning
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Zero initialization tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct GlobalVariableTest {
> + int i;
> +
> + GlobalVariableTest() {}
> +};
> +
> +GlobalVariableTest gvt; // no-warning
> +
> +//===----------------------------------------------------------------------===//
> +// Copy and move constructor tests.
> +//===----------------------------------------------------------------------===//
> +
> +template <class T>
> +void funcToSquelchCompilerWarnings(const T &t);
> +
> +#ifdef PEDANTIC
> +struct CopyConstructorTest {
> + int i; // expected-note{{uninitialized field 'this->i'}}
> +
> + CopyConstructorTest() : i(1337) {}
> + CopyConstructorTest(const CopyConstructorTest &other) {}
> +};
> +
> +void fCopyConstructorTest() {
> + CopyConstructorTest cct;
> + CopyConstructorTest copy = cct; // expected-warning{{1 uninitialized field}}
> + funcToSquelchCompilerWarnings(copy);
> +}
> +#else
> +struct CopyConstructorTest {
> + int i;
> +
> + CopyConstructorTest() : i(1337) {}
> + CopyConstructorTest(const CopyConstructorTest &other) {}
> +};
> +
> +void fCopyConstructorTest() {
> + CopyConstructorTest cct;
> + CopyConstructorTest copy = cct;
> + funcToSquelchCompilerWarnings(copy);
> +}
> +#endif // PEDANTIC
> +
> +struct MoveConstructorTest {
> + // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
> + int i; // no-note
> +
> + MoveConstructorTest() : i(1337) {}
> + MoveConstructorTest(const CopyConstructorTest &other) = delete;
> + MoveConstructorTest(const CopyConstructorTest &&other) {}
> +};
> +
> +void fMoveConstructorTest() {
> + MoveConstructorTest cct;
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + MoveConstructorTest copy(static_cast<MoveConstructorTest &&>(cct)); // no-warning
> + funcToSquelchCompilerWarnings(copy);
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Array tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct IntArrayTest {
> + int arr[256];
> +
> + IntArrayTest() {
> + // All good!
> + }
> +};
> +
> +void fIntArrayTest() {
> + IntArrayTest();
> +}
> +
> +struct RecordTypeArrayTest {
> + struct RecordType {
> + int x, y;
> + } arr[256];
> +
> + RecordTypeArrayTest() {
> + // All good!
> + }
> +};
> +
> +void fRecordTypeArrayTest() {
> + RecordTypeArrayTest();
> +}
> +
> +template <class T>
> +class CharArrayPointerTest {
> + T *t; // no-crash
> +
> +public:
> + CharArrayPointerTest(T *t, int) : t(t) {}
> +};
> +
> +void fCharArrayPointerTest() {
> + char str[16] = "012345678912345";
> + CharArrayPointerTest<char[16]>(&str, int());
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Memset tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct MemsetTest1 {
> + int a, b, c;
> +
> + MemsetTest1() {
> + __builtin_memset(this, 0, sizeof(decltype(*this)));
> + }
> +};
> +
> +void fMemsetTest1() {
> + MemsetTest1();
> +}
> +
> +struct MemsetTest2 {
> + int a;
> +
> + MemsetTest2() {
> + __builtin_memset(&a, 0, sizeof(int));
> + }
> +};
> +
> +void fMemsetTest2() {
> + MemsetTest2();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Lambda tests.
> +//===----------------------------------------------------------------------===//
> +
> +template <class Callable>
> +struct LambdaTest1 {
> + Callable functor;
> +
> + LambdaTest1(const Callable &functor, int) : functor(functor) {
> + // All good!
> + }
> +};
> +
> +void fLambdaTest1() {
> + auto isEven = [](int a) { return a % 2 == 0; };
> + LambdaTest1<decltype(isEven)>(isEven, int());
> +}
> +
> +#ifdef PEDANTIC
> +template <class Callable>
> +struct LambdaTest2 {
> + Callable functor;
> +
> + LambdaTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fLambdaTest2() {
> + int b;
> + auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.'}}
> + LambdaTest2<decltype(equals)>(equals, int());
> +}
> +#else
> +template <class Callable>
> +struct LambdaTest2 {
> + Callable functor;
> +
> + LambdaTest2(const Callable &functor, int) : functor(functor) {}
> +};
> +
> +void fLambdaTest2() {
> + int b;
> + auto equals = [&b](int a) { return a == b; };
> + LambdaTest2<decltype(equals)>(equals, int());
> +}
> +#endif //PEDANTIC
> +
> +#ifdef PEDANTIC
> +namespace LT3Detail {
> +
> +struct RecordType {
> + int x; // expected-note{{uninitialized field 'this->functor..x'}}
> + int y; // expected-note{{uninitialized field 'this->functor..y'}}
> +};
> +
> +} // namespace LT3Detail
> +template <class Callable>
> +struct LambdaTest3 {
> + Callable functor;
> +
> + LambdaTest3(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized fields}}
> +};
> +
> +void fLambdaTest3() {
> + LT3Detail::RecordType rec1;
> + auto equals = [&rec1](LT3Detail::RecordType rec2) {
> + return rec1.x == rec2.x;
> + };
> + LambdaTest3<decltype(equals)>(equals, int());
> +}
> +#else
> +namespace LT3Detail {
> +
> +struct RecordType {
> + int x;
> + int y;
> +};
> +
> +} // namespace LT3Detail
> +template <class Callable>
> +struct LambdaTest3 {
> + Callable functor;
> +
> + LambdaTest3(const Callable &functor, int) : functor(functor) {}
> +};
> +
> +void fLambdaTest3() {
> + LT3Detail::RecordType rec1;
> + auto equals = [&rec1](LT3Detail::RecordType rec2) {
> + return rec1.x == rec2.x;
> + };
> + LambdaTest3<decltype(equals)>(equals, int());
> +}
> +#endif //PEDANTIC
> +
> +//===----------------------------------------------------------------------===//
> +// System header tests.
> +//===----------------------------------------------------------------------===//
> +
> +#include "Inputs/system-header-simulator-for-cxx-uninitialized-object.h"
> +
> +struct SystemHeaderTest1 {
> + RecordInSystemHeader rec; // defined in the system header simulator
> +
> + SystemHeaderTest1() {
> + // All good!
> + }
> +};
> +
> +void fSystemHeaderTest1() {
> + SystemHeaderTest1();
> +}
> +
> +#ifdef PEDANTIC
> +struct SystemHeaderTest2 {
> + struct RecordType {
> + int x; // expected-note{{uninitialized field 'this->container.t.x}}
> + int y; // expected-note{{uninitialized field 'this->container.t.y}}
> + };
> + ContainerInSystemHeader<RecordType> container;
> +
> + SystemHeaderTest2(RecordType &rec, int) : container(rec) {} // expected-warning{{2 uninitialized fields}}
> +};
> +
> +void fSystemHeaderTest2() {
> + SystemHeaderTest2::RecordType rec;
> + SystemHeaderTest2(rec, int());
> +}
> +#else
> +struct SystemHeaderTest2 {
> + struct RecordType {
> + int x;
> + int y;
> + };
> + ContainerInSystemHeader<RecordType> container;
> +
> + SystemHeaderTest2(RecordType &rec, int) : container(rec) {}
> +};
> +
> +void fSystemHeaderTest2() {
> + SystemHeaderTest2::RecordType rec;
> + SystemHeaderTest2(rec, int());
> +}
> +#endif //PEDANTIC
> +
> +//===----------------------------------------------------------------------===//
> +// Incomplete type tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct IncompleteTypeTest1 {
> + struct RecordType;
> + // no-crash
> + RecordType *recptr; // expected-note{{uninitialized pointer 'this->recptr}}
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + IncompleteTypeTest1() {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fIncompleteTypeTest1() {
> + IncompleteTypeTest1();
> +}
> +
> +struct IncompleteTypeTest2 {
> + struct RecordType;
> + RecordType *recptr; // no-crash
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + RecordType *recordTypeFactory();
> +
> + IncompleteTypeTest2() : recptr(recordTypeFactory()) {}
> +};
> +
> +void fIncompleteTypeTest2() {
> + IncompleteTypeTest2();
> +}
> +
> +struct IncompleteTypeTest3 {
> + struct RecordType;
> + RecordType &recref; // no-crash
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + RecordType &recordTypeFactory();
> +
> + IncompleteTypeTest3() : recref(recordTypeFactory()) {}
> +};
> +
> +void fIncompleteTypeTest3() {
> + IncompleteTypeTest3();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Builtin type or enumeration type related tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct IntegralTypeTest {
> + int a; // expected-note{{uninitialized field 'this->a'}}
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + IntegralTypeTest() {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fIntegralTypeTest() {
> + IntegralTypeTest();
> +}
> +
> +struct FloatingTypeTest {
> + float a; // expected-note{{uninitialized field 'this->a'}}
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + FloatingTypeTest() {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fFloatingTypeTest() {
> + FloatingTypeTest();
> +}
> +
> +struct NullptrTypeTypeTest {
> + decltype(nullptr) a; // expected-note{{uninitialized field 'this->a'}}
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + NullptrTypeTypeTest() {} // expected-warning{{1 uninitialized field}}
> +};
> +
> +void fNullptrTypeTypeTest() {
> + NullptrTypeTypeTest();
> +}
> +
> +struct EnumTest {
> + enum Enum {
> + A,
> + B
> + } enum1; // expected-note{{uninitialized field 'this->enum1'}}
> + enum class Enum2 {
> + A,
> + B
> + } enum2; // expected-note{{uninitialized field 'this->enum2'}}
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + EnumTest() {} // expected-warning{{2 uninitialized fields}}
> +};
> +
> +void fEnumTest() {
> + EnumTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// Tests for constructor calls within another cunstructor, without the two
> +// records being in any relation.
> +//===----------------------------------------------------------------------===//
> +
> +void halt() __attribute__((__noreturn__));
> +void assert(int b) {
> + if (!b)
> + halt();
> +}
> +
> +// While a singleton would make more sense as a static variable, that would zero
> +// initialize all of its fields, hence the not too practical implementation.
> +struct Singleton {
> + // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
> + int i; // no-note
> +
> + Singleton() {
> + assert(!isInstantiated);
> + // TODO: we'd expect the warning: {{1 uninitialized field}}
> + isInstantiated = true; // no-warning
> + }
> +
> + ~Singleton() {
> + isInstantiated = false;
> + }
> +
> + static bool isInstantiated;
> +};
> +
> +bool Singleton::isInstantiated = false;
> +
> +struct SingletonTest {
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + SingletonTest() {
> + Singleton();
> + }
> +};
> +
> +void fSingletonTest() {
> + SingletonTest();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// C++11 member initializer tests.
> +//===----------------------------------------------------------------------===//
> +
> +struct CXX11MemberInitTest1 {
> + int a = 3;
> + int b;
> + CXX11MemberInitTest1() : b(2) {
> + // All good!
> + }
> +};
> +
> +void fCXX11MemberInitTest1() {
> + CXX11MemberInitTest1();
> +}
> +
> +struct CXX11MemberInitTest2 {
> + struct RecordType {
> + // TODO: we'd expect the note: {{uninitialized field 'this->rec.a'}}
> + int a; // no-note
> + // TODO: we'd expect the note: {{uninitialized field 'this->rec.b'}}
> + int b; // no-note
> +
> + RecordType(int) {}
> + };
> +
> + RecordType rec = RecordType(int());
> + int dontGetFilteredByNonPedanticMode = 0;
> +
> + CXX11MemberInitTest2() {}
> +};
> +
> +void fCXX11MemberInitTest2() {
> + // TODO: we'd expect the warning: {{2 uninitializeds field}}
> + CXX11MemberInitTest2(); // no-warning
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
More information about the cfe-commits
mailing list