865 lines
22 KiB
Plaintext
865 lines
22 KiB
Plaintext
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s
|
|
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s
|
|
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s
|
|
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %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(const POD &pp) {
|
|
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}}
|
|
|
|
// Copy from symbolic references correctly.
|
|
POD p4 = pp;
|
|
// Make sure that p4.x contains a symbol after copy.
|
|
if (p4.x > 0)
|
|
clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
|
|
// FIXME: Element region gets in the way, so these aren't the same symbols
|
|
// as they should be.
|
|
clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
|
|
|
|
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() {
|
|
raw_pair *pp = new raw_pair();
|
|
clang_analyzer_eval(pp->p1 == 0); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(pp->p2 == 0); // expected-warning{{TRUE}}
|
|
}
|
|
|
|
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.
|
|
}
|
|
};
|
|
|
|
class Empty {
|
|
public:
|
|
static int glob;
|
|
Empty(); // No body.
|
|
Empty(int x); // Body below.
|
|
};
|
|
|
|
class PairContainer : public Empty {
|
|
public:
|
|
raw_pair p;
|
|
int q;
|
|
PairContainer() : Empty(), p() {
|
|
// This previously caused a crash because the empty base class looked
|
|
// like an initialization of 'p'.
|
|
}
|
|
PairContainer(int) : Empty(), p() {
|
|
// Test inlining something else here.
|
|
}
|
|
PairContainer(double): Empty(1), p() {
|
|
clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(q == 1); // expected-warning{{TRUE}}
|
|
|
|
// This one's indeed UNKNOWN. Definitely not TRUE.
|
|
clang_analyzer_eval(p.p2 == glob); // expected-warning{{UNKNOWN}}
|
|
}
|
|
};
|
|
|
|
Empty::Empty(int x) {
|
|
static_cast<PairContainer *>(this)->p.p1 = x;
|
|
static_cast<PairContainer *>(this)->q = x;
|
|
// Our static member will store the old garbage values of fields that aren't
|
|
// yet initialized. It's not certainly garbage though (i.e. the constructor
|
|
// could have been called on an initialized piece of memory), so no
|
|
// uninitialized value warning here, and it should be a symbol, not
|
|
// undefined value, for later comparison.
|
|
glob = static_cast<PairContainer *>(this)->p.p2;
|
|
}
|
|
|
|
class Empty2 {
|
|
public:
|
|
static int glob_p1, glob_p2;
|
|
Empty2(); // Body below.
|
|
};
|
|
|
|
class PairDoubleEmptyContainer: public Empty, public Empty2 {
|
|
public:
|
|
raw_pair p;
|
|
PairDoubleEmptyContainer(): Empty(), Empty2(), p() {
|
|
clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
|
|
|
|
// This is indeed UNKNOWN.
|
|
clang_analyzer_eval(p.p1 == glob_p1); // expected-warning{{UNKNOWN}}
|
|
clang_analyzer_eval(p.p2 == glob_p2); // expected-warning{{UNKNOWN}}
|
|
}
|
|
};
|
|
|
|
Empty2::Empty2() {
|
|
glob_p1 = static_cast<PairDoubleEmptyContainer *>(this)->p.p1;
|
|
glob_p2 = static_cast<PairDoubleEmptyContainer *>(this)->p.p2;
|
|
}
|
|
|
|
class PairContainerContainer {
|
|
int padding;
|
|
PairContainer pc;
|
|
public:
|
|
PairContainerContainer() : pc(1) {}
|
|
};
|
|
}
|
|
|
|
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};
|
|
clang_analyzer_eval(list->usedInitializerList); // expected-warning{{TRUE}}
|
|
}
|
|
}
|
|
|
|
namespace PR19579 {
|
|
class C {};
|
|
|
|
void f() {
|
|
C();
|
|
int a;
|
|
|
|
extern void use(int);
|
|
use(a); // expected-warning{{uninitialized}}
|
|
}
|
|
|
|
void g() {
|
|
struct S {
|
|
C c;
|
|
int i;
|
|
};
|
|
|
|
// This order triggers the initialization of the inner "a" after the
|
|
// constructor for "C" is run, which used to confuse the analyzer
|
|
// (is "C()" the initialization of "a"?).
|
|
struct S s = {
|
|
C(),
|
|
({
|
|
int a, b = 0;
|
|
0;
|
|
})
|
|
};
|
|
}
|
|
}
|
|
|
|
namespace NoCrashOnEmptyBaseOptimization {
|
|
struct NonEmptyBase {
|
|
int X;
|
|
explicit NonEmptyBase(int X) : X(X) {}
|
|
};
|
|
|
|
struct EmptyBase {};
|
|
|
|
struct S : NonEmptyBase, EmptyBase {
|
|
S() : NonEmptyBase(0), EmptyBase() {}
|
|
};
|
|
|
|
void testSCtorNoCrash() {
|
|
S s;
|
|
}
|
|
}
|
|
|
|
namespace EmptyBaseAssign {
|
|
struct B1 {};
|
|
struct B2 { int x; };
|
|
struct D: public B1, public B2 {
|
|
const D &operator=(const D &d) {
|
|
*((B2 *)this) = d;
|
|
*((B1 *)this) = d;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
void test() {
|
|
D d1;
|
|
d1.x = 1;
|
|
D d2;
|
|
d2 = d1;
|
|
clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}}
|
|
}
|
|
}
|
|
|
|
namespace vbase_zero_init {
|
|
class A {
|
|
virtual void foo();
|
|
};
|
|
|
|
class B {
|
|
virtual void bar();
|
|
public:
|
|
static int glob_y, glob_z, glob_w;
|
|
int x;
|
|
B(); // Body below.
|
|
};
|
|
|
|
class C : virtual public A {
|
|
public:
|
|
int y;
|
|
};
|
|
|
|
class D : public B, public C {
|
|
public:
|
|
// 'z', unlike 'w', resides in an area that would have been within padding of
|
|
// base class 'C' if it wasn't part of 'D', but only on 64-bit systems.
|
|
int z, w;
|
|
// Initialization order: A(), B(), C().
|
|
D() : A(), C() {
|
|
clang_analyzer_eval(x == 1); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(y == 0); // expected-warning{{TRUE}}
|
|
#ifdef I386
|
|
clang_analyzer_eval(z == 3); // expected-warning{{TRUE}}
|
|
#else
|
|
// FIXME: Should be TRUE. Initialized in B().
|
|
clang_analyzer_eval(z == 3); // expected-warning{{UNKNOWN}}
|
|
#endif
|
|
clang_analyzer_eval(w == 4); // expected-warning{{TRUE}}
|
|
|
|
// FIXME: Should be UNKNOWN. Changed in B() since glob_y was assigned.
|
|
clang_analyzer_eval(y == glob_y); // expected-warning{{TRUE}}
|
|
|
|
#ifdef I386
|
|
clang_analyzer_eval(z == glob_z); // expected-warning{{UNKNOWN}}
|
|
#else
|
|
// FIXME: Should be UNKNOWN. Changed in B() since glob_z was assigned.
|
|
clang_analyzer_eval(z == glob_z); // expected-warning{{TRUE}}
|
|
#endif
|
|
|
|
clang_analyzer_eval(w == glob_w); // expected-warning{{UNKNOWN}}
|
|
} // no-crash
|
|
};
|
|
|
|
B::B() : x(1) {
|
|
// Our static members will store the old garbage values of fields that aren't
|
|
// yet initialized. These aren't certainly garbage though (i.e. the
|
|
// constructor could have been called on an initialized piece of memory),
|
|
// so no uninitialized value warning here, and these should be symbols, not
|
|
// undefined values, for later comparison.
|
|
glob_y = static_cast<D *>(this)->y;
|
|
glob_z = static_cast<D *>(this)->z;
|
|
glob_w = static_cast<D *>(this)->w;
|
|
static_cast<D *>(this)->y = 2;
|
|
static_cast<D *>(this)->z = 3;
|
|
static_cast<D *>(this)->w = 4;
|
|
}
|
|
}
|