// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \ // RUN: -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \ // RUN: -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \ // RUN: -std=c++14 -verify %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \ // RUN: -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \ // RUN: -std=c++14 -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 IntTemplateClassTest1 { T t; int b; public: IntTemplateClassTest1(T i) { b = 21; t = i; // All good! } }; void fIntTemplateClassTest1() { IntTemplateClassTest1(22); } template class IntTemplateClassTest2 { T t; // expected-note{{uninitialized field 'this->t'}} int b; public: IntTemplateClassTest2() { b = 23; // expected-warning{{1 uninitialized field}} } }; void fIntTemplateClassTest2() { IntTemplateClassTest2(); } struct Record { int x; // expected-note{{uninitialized field 'this->t.x'}} int y; // expected-note{{uninitialized field 'this->t.y'}} }; template class RecordTemplateClassTest { T t; int b; public: RecordTemplateClassTest() { b = 24; // expected-warning{{2 uninitialized fields}} } }; void fRecordTemplateClassTest() { RecordTemplateClassTest(); } //===----------------------------------------------------------------------===// // Tests involving functions with unknown implementations. //===----------------------------------------------------------------------===// template void mayInitialize(T &); template void wontInitialize(const T &); class PassingToUnknownFunctionTest1 { int a, b; public: PassingToUnknownFunctionTest1() { mayInitialize(a); mayInitialize(b); // All good! } PassingToUnknownFunctionTest1(int) { mayInitialize(a); // All good! } PassingToUnknownFunctionTest1(int, int) { mayInitialize(*this); // All good! } }; void 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 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(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 CharArrayPointerTest { T *t; // no-crash public: CharArrayPointerTest(T *t, int) : t(t) {} }; void fCharArrayPointerTest() { char str[16] = "012345678912345"; CharArrayPointerTest(&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 struct LambdaThisTest { Callable functor; LambdaThisTest(const Callable &functor, int) : functor(functor) { // All good! } }; struct HasCapturableThis { void fLambdaThisTest() { auto isEven = [this](int a) { return a % 2 == 0; }; // no-crash LambdaThisTest(isEven, int()); } }; template struct LambdaTest1 { Callable functor; LambdaTest1(const Callable &functor, int) : functor(functor) { // All good! } }; void fLambdaTest1() { auto isEven = [](int a) { return a % 2 == 0; }; LambdaTest1(isEven, int()); } #ifdef PEDANTIC template 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 pointee 'this->functor./*captured variable*/b'}} LambdaTest2(equals, int()); } #else template struct LambdaTest2 { Callable functor; LambdaTest2(const Callable &functor, int) : functor(functor) {} }; void fLambdaTest2() { int b; auto equals = [&b](int a) { return a == b; }; LambdaTest2(equals, int()); } #endif //PEDANTIC #ifdef PEDANTIC namespace LT3Detail { struct RecordType { int x; // expected-note{{uninitialized field 'this->functor./*captured variable*/rec1.x'}} int y; // expected-note{{uninitialized field 'this->functor./*captured variable*/rec1.y'}} }; } // namespace LT3Detail template 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(equals, int()); } #else namespace LT3Detail { struct RecordType { int x; int y; }; } // namespace LT3Detail template 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(equals, int()); } #endif //PEDANTIC template struct MultipleLambdaCapturesTest1 { Callable functor; int dontGetFilteredByNonPedanticMode = 0; MultipleLambdaCapturesTest1(const Callable &functor, int) : functor(functor) {} // expected-warning{{2 uninitialized field}} }; void fMultipleLambdaCapturesTest1() { int b1, b2 = 3, b3; auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor./*captured variable*/b1'}} // expected-note@-1{{uninitialized pointee 'this->functor./*captured variable*/b3'}} MultipleLambdaCapturesTest1(equals, int()); } template struct MultipleLambdaCapturesTest2 { Callable functor; int dontGetFilteredByNonPedanticMode = 0; MultipleLambdaCapturesTest2(const Callable &functor, int) : functor(functor) {} // expected-warning{{1 uninitialized field}} }; void fMultipleLambdaCapturesTest2() { int b1, b2 = 3, b3; auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor./*captured variable*/b3'}} MultipleLambdaCapturesTest2(equals, int()); } struct LambdaWrapper { void *func; // no-crash int dontGetFilteredByNonPedanticMode = 0; LambdaWrapper(void *ptr) : func(ptr) {} // expected-warning{{1 uninitialized field}} }; struct ThisCapturingLambdaFactory { int a; // expected-note{{uninitialized field 'static_cast(this->func)->/*'this' capture*/->a'}} auto ret() { return [this] { (void)this; }; } }; void fLambdaFieldWithInvalidThisCapture() { void *ptr; { ThisCapturingLambdaFactory a; decltype(a.ret()) lambda = a.ret(); ptr = λ } LambdaWrapper t(ptr); } //===----------------------------------------------------------------------===// // 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 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 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 { int i; // expected-note{{uninitialized field 'this->i'}} int dontGetFilteredByNonPedanticMode = 0; Singleton() { assert(!isInstantiated); isInstantiated = true; // expected-warning{{1 uninitialized field}} } ~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 }