// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s #include "Inputs/system-header-simulator-cxx.h" void clang_analyzer_eval(bool); void clang_analyzer_checkInlined(bool); // A simplified version of std::move. template <typename T> T &&move(T &obj) { return static_cast<T &&>(obj); } struct Wrapper { __strong id obj; }; void test() { Wrapper w; // force a diagnostic *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} } struct IntWrapper { int x; }; void testCopyConstructor() { IntWrapper a; a.x = 42; IntWrapper b(a); clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} } struct NonPODIntWrapper { int x; virtual int get(); }; void testNonPODCopyConstructor() { NonPODIntWrapper a; a.x = 42; NonPODIntWrapper b(a); clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}} } namespace ConstructorVirtualCalls { class A { public: int *out1, *out2, *out3; virtual int get() { return 1; } A(int *out1) { *out1 = get(); } }; class B : public A { public: virtual int get() { return 2; } B(int *out1, int *out2) : A(out1) { *out2 = get(); } }; class C : public B { public: virtual int get() { return 3; } C(int *out1, int *out2, int *out3) : B(out1, out2) { *out3 = get(); } }; void test() { int a, b, c; C obj(&a, &b, &c); clang_analyzer_eval(a == 1); // expected-warning{{TRUE}} clang_analyzer_eval(b == 2); // expected-warning{{TRUE}} clang_analyzer_eval(c == 3); // expected-warning{{TRUE}} clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}} // Sanity check for devirtualization. A *base = &obj; clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}} } } namespace TemporaryConstructor { class BoolWrapper { public: BoolWrapper() { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} value = true; } bool value; }; void test() { // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined. if (BoolWrapper().value) return; } } namespace ConstructorUsedAsRValue { using TemporaryConstructor::BoolWrapper; bool extractValue(BoolWrapper b) { return b.value; } void test() { bool result = extractValue(BoolWrapper()); clang_analyzer_eval(result); // expected-warning{{TRUE}} } } namespace PODUninitialized { class POD { public: int x, y; }; class PODWrapper { public: POD p; }; class NonPOD { public: int x, y; NonPOD() {} NonPOD(const NonPOD &Other) : x(Other.x), y(Other.y) // expected-warning {{undefined}} { } NonPOD(NonPOD &&Other) : x(Other.x), y(Other.y) // expected-warning {{undefined}} { } NonPOD &operator=(const NonPOD &Other) { x = Other.x; y = Other.y; // expected-warning {{undefined}} return *this; } NonPOD &operator=(NonPOD &&Other) { x = Other.x; y = Other.y; // expected-warning {{undefined}} return *this; } }; class NonPODWrapper { public: class Inner { public: int x, y; Inner() {} Inner(const Inner &Other) : x(Other.x), y(Other.y) // expected-warning {{undefined}} { } Inner(Inner &&Other) : x(Other.x), y(Other.y) // expected-warning {{undefined}} { } Inner &operator=(const Inner &Other) { x = Other.x; // expected-warning {{undefined}} y = Other.y; return *this; } Inner &operator=(Inner &&Other) { x = Other.x; // expected-warning {{undefined}} y = Other.y; return *this; } }; Inner p; }; void testPOD() { POD p; p.x = 1; POD p2 = p; // no-warning clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} POD p3 = move(p); // no-warning clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} // Use rvalues as well. clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} PODWrapper w; w.p.y = 1; PODWrapper w2 = w; // no-warning clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} PODWrapper w3 = move(w); // no-warning clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} // Use rvalues as well. clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}} } void testNonPOD() { NonPOD p; p.x = 1; NonPOD p2 = p; } void testNonPODMove() { NonPOD p; p.x = 1; NonPOD p2 = move(p); } void testNonPODWrapper() { NonPODWrapper w; w.p.y = 1; NonPODWrapper w2 = w; } void testNonPODWrapperMove() { NonPODWrapper w; w.p.y = 1; NonPODWrapper w2 = move(w); } // Not strictly about constructors, but trivial assignment operators should // essentially work the same way. namespace AssignmentOperator { void testPOD() { POD p; p.x = 1; POD p2; p2 = p; // no-warning clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}} POD p3; p3 = move(p); // no-warning clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}} PODWrapper w; w.p.y = 1; PODWrapper w2; w2 = w; // no-warning clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}} PODWrapper w3; w3 = move(w); // no-warning clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}} } void testReturnValue() { POD p; p.x = 1; POD p2; clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}} PODWrapper w; w.p.y = 1; PODWrapper w2; clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}} } void testNonPOD() { NonPOD p; p.x = 1; NonPOD p2; p2 = p; } void testNonPODMove() { NonPOD p; p.x = 1; NonPOD p2; p2 = move(p); } void testNonPODWrapper() { NonPODWrapper w; w.p.y = 1; NonPODWrapper w2; w2 = w; } void testNonPODWrapperMove() { NonPODWrapper w; w.p.y = 1; NonPODWrapper w2; w2 = move(w); } } } namespace ArrayMembers { struct Primitive { int values[3]; }; void testPrimitive() { Primitive a = { { 1, 2, 3 } }; clang_analyzer_eval(a.values[0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[2] == 3); // expected-warning{{TRUE}} Primitive b = a; clang_analyzer_eval(b.values[0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[2] == 3); // expected-warning{{TRUE}} Primitive c; c = b; clang_analyzer_eval(c.values[0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[2] == 3); // expected-warning{{TRUE}} } struct NestedPrimitive { int values[2][3]; }; void testNestedPrimitive() { NestedPrimitive a = { { { 0, 0, 0 }, { 1, 2, 3 } } }; clang_analyzer_eval(a.values[1][0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][2] == 3); // expected-warning{{TRUE}} NestedPrimitive b = a; clang_analyzer_eval(b.values[1][0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1][1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1][2] == 3); // expected-warning{{TRUE}} NestedPrimitive c; c = b; clang_analyzer_eval(c.values[1][0] == 1); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1][1] == 2); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1][2] == 3); // expected-warning{{TRUE}} } struct POD { IntWrapper values[3]; }; void testPOD() { POD a = { { { 1 }, { 2 }, { 3 } } }; clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} POD b = a; clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{TRUE}} POD c; c = b; clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{TRUE}} } struct NestedPOD { IntWrapper values[2][3]; }; void testNestedPOD() { NestedPOD a = { { { { 0 }, { 0 }, { 0 } }, { { 1 }, { 2 }, { 3 } } } }; clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}} NestedPOD b = a; clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{TRUE}} NestedPOD c; c = b; clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{TRUE}} } struct NonPOD { NonPODIntWrapper values[3]; }; void testNonPOD() { NonPOD a; a.values[0].x = 1; a.values[1].x = 2; a.values[2].x = 3; clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} NonPOD b = a; clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}} NonPOD c; c = b; clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}} } struct NestedNonPOD { NonPODIntWrapper values[2][3]; }; void testNestedNonPOD() { NestedNonPOD a; a.values[0][0].x = 0; a.values[0][1].x = 0; a.values[0][2].x = 0; a.values[1][0].x = 1; a.values[1][1].x = 2; a.values[1][2].x = 3; clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}} NestedNonPOD b = a; clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{UNKNOWN}} NestedNonPOD c; c = b; clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{UNKNOWN}} } struct NonPODDefaulted { NonPODIntWrapper values[3]; NonPODDefaulted() = default; NonPODDefaulted(const NonPODDefaulted &) = default; NonPODDefaulted &operator=(const NonPODDefaulted &) = default; }; void testNonPODDefaulted() { NonPODDefaulted a; a.values[0].x = 1; a.values[1].x = 2; a.values[2].x = 3; clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}} clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}} NonPODDefaulted b = a; clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}} NonPODDefaulted c; c = b; clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}} } }; namespace VirtualInheritance { int counter; struct base { base() { ++counter; } }; struct virtual_subclass : public virtual base { virtual_subclass() {} }; struct double_subclass : public virtual_subclass { double_subclass() {} }; void test() { counter = 0; double_subclass obj; clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}} } struct double_virtual_subclass : public virtual virtual_subclass { double_virtual_subclass() {} }; void testVirtual() { counter = 0; double_virtual_subclass obj; clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}} } } namespace ZeroInitialization { struct raw_pair { int p1; int p2; }; void testVarDecl() { raw_pair p{}; clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} } void testTemporary() { clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}} } void testArray() { raw_pair p[2] = {}; clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}} } void testNew() { // FIXME: Pending proper implementation of constructors for 'new'. raw_pair *pp = new raw_pair(); clang_analyzer_eval(pp->p1 == 0); // expected-warning{{UNKNOWN}} clang_analyzer_eval(pp->p2 == 0); // expected-warning{{UNKNOWN}} } void testArrayNew() { // FIXME: Pending proper implementation of constructors for 'new[]'. raw_pair *p = new raw_pair[2](); clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}} clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}} clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}} clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}} } struct initializing_pair { public: int x; raw_pair y; initializing_pair() : x(), y() {} }; void testFieldInitializers() { initializing_pair p; clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}} } struct subclass : public raw_pair { subclass() = default; }; void testSubclass() { subclass p; clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}} } struct initializing_subclass : public raw_pair { initializing_subclass() : raw_pair() {} }; void testInitializingSubclass() { initializing_subclass p; clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}} clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}} } struct pair_wrapper { pair_wrapper() : p() {} raw_pair p; }; struct virtual_subclass : public virtual pair_wrapper { virtual_subclass() {} }; struct double_virtual_subclass : public virtual_subclass { double_virtual_subclass() { // This previously caused a crash because the pair_wrapper subobject was // initialized twice. } }; } namespace InitializerList { struct List { bool usedInitializerList; List() : usedInitializerList(false) {} List(std::initializer_list<int>) : usedInitializerList(true) {} }; void testStatic() { List defaultCtor; clang_analyzer_eval(!defaultCtor.usedInitializerList); // expected-warning{{TRUE}} List list{1, 2}; clang_analyzer_eval(list.usedInitializerList); // expected-warning{{TRUE}} } void testDynamic() { List *list = new List{1, 2}; // FIXME: When we handle constructors with 'new', this will be TRUE. clang_analyzer_eval(list->usedInitializerList); // expected-warning{{UNKNOWN}} } }