932 lines
22 KiB
C++
932 lines
22 KiB
C++
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
|
||
|
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
|
||
|
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
|
||
|
// RUN: -std=c++11 -verify %s
|
||
|
|
||
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
|
||
|
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
|
||
|
// RUN: -std=c++11 -verify %s
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Concrete location tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct ConcreteIntLocTest {
|
||
|
int *ptr;
|
||
|
|
||
|
ConcreteIntLocTest() : ptr(reinterpret_cast<int *>(0xDEADBEEF)) {}
|
||
|
};
|
||
|
|
||
|
void fConcreteIntLocTest() {
|
||
|
ConcreteIntLocTest();
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// nonloc::LocAsInteger tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
using intptr_t = unsigned long long;
|
||
|
|
||
|
struct LocAsIntegerTest {
|
||
|
intptr_t ptr; // expected-note{{uninitialized pointee 'reinterpret_cast<char *>(this->ptr)'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
LocAsIntegerTest(void *ptr) : ptr(reinterpret_cast<intptr_t>(ptr)) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fLocAsIntegerTest() {
|
||
|
char c;
|
||
|
LocAsIntegerTest t(&c);
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// 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();
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Alloca tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct UntypedAllocaTest {
|
||
|
void *allocaPtr;
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
UntypedAllocaTest() : allocaPtr(__builtin_alloca(sizeof(int))) {
|
||
|
// All good!
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fUntypedAllocaTest() {
|
||
|
UntypedAllocaTest();
|
||
|
}
|
||
|
|
||
|
struct TypedAllocaTest1 {
|
||
|
int *allocaPtr; // expected-note{{uninitialized pointee 'this->allocaPtr'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
TypedAllocaTest1() // expected-warning{{1 uninitialized field}}
|
||
|
: allocaPtr(static_cast<int *>(__builtin_alloca(sizeof(int)))) {}
|
||
|
};
|
||
|
|
||
|
void fTypedAllocaTest1() {
|
||
|
TypedAllocaTest1();
|
||
|
}
|
||
|
|
||
|
struct TypedAllocaTest2 {
|
||
|
int *allocaPtr;
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
TypedAllocaTest2()
|
||
|
: allocaPtr(static_cast<int *>(__builtin_alloca(sizeof(int)))) {
|
||
|
*allocaPtr = 55555;
|
||
|
// All good!
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fTypedAllocaTest2() {
|
||
|
TypedAllocaTest2();
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// 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 VectorSizePointer {
|
||
|
VectorSizePointer() {} // expected-warning{{1 uninitialized field}}
|
||
|
__attribute__((__vector_size__(8))) int *x; // expected-note{{uninitialized pointer 'this->x'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
};
|
||
|
|
||
|
void __vector_size__PointerTest() {
|
||
|
VectorSizePointer v;
|
||
|
}
|
||
|
|
||
|
struct VectorSizePointee {
|
||
|
using MyVectorType = __attribute__((__vector_size__(8))) int;
|
||
|
MyVectorType *x;
|
||
|
|
||
|
VectorSizePointee(decltype(x) x) : x(x) {}
|
||
|
};
|
||
|
|
||
|
void __vector_size__PointeeTest() {
|
||
|
VectorSizePointee::MyVectorType i;
|
||
|
// TODO: Report v.x's pointee.
|
||
|
VectorSizePointee v(&i);
|
||
|
}
|
||
|
|
||
|
struct CyclicPointerTest1 {
|
||
|
int *ptr; // expected-note{{object references itself 'this->ptr'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fCyclicPointerTest1() {
|
||
|
CyclicPointerTest1();
|
||
|
}
|
||
|
|
||
|
struct CyclicPointerTest2 {
|
||
|
int **pptr; // expected-note{{object references itself 'this->pptr'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fCyclicPointerTest2() {
|
||
|
CyclicPointerTest2();
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// 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; // expected-note {{here}}
|
||
|
|
||
|
public:
|
||
|
VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}}
|
||
|
// All good!
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fVoidPointerRRefTest1() {
|
||
|
void *vptr = malloc(sizeof(int));
|
||
|
VoidPointerRRefTest1(vptr, char());
|
||
|
}
|
||
|
|
||
|
class VoidPointerRRefTest2 {
|
||
|
void **&&vpptrrref; // expected-note {{here}}
|
||
|
|
||
|
public:
|
||
|
VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) { // expected-warning {{binding reference member 'vpptrrref' to stack allocated parameter 'vptr'}}
|
||
|
// All good!
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fVoidPointerRRefTest2() {
|
||
|
void *vptr = malloc(sizeof(int));
|
||
|
VoidPointerRRefTest2(&vptr, char());
|
||
|
}
|
||
|
|
||
|
class VoidPointerLRefTest {
|
||
|
void *&vptrrref; // expected-note {{here}}
|
||
|
|
||
|
public:
|
||
|
VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}}
|
||
|
// All good!
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fVoidPointerLRefTest() {
|
||
|
void *vptr = malloc(sizeof(int));
|
||
|
VoidPointerLRefTest(vptr, char());
|
||
|
}
|
||
|
|
||
|
struct CyclicVoidPointerTest {
|
||
|
void *vptr; // expected-note{{object references itself 'this->vptr'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
CyclicVoidPointerTest() : vptr(&vptr) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fCyclicVoidPointerTest() {
|
||
|
CyclicVoidPointerTest();
|
||
|
}
|
||
|
|
||
|
struct IntDynTypedVoidPointerTest1 {
|
||
|
void *vptr; // expected-note{{uninitialized pointee 'static_cast<int *>(this->vptr)'}}
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fIntDynTypedVoidPointerTest1() {
|
||
|
int a;
|
||
|
IntDynTypedVoidPointerTest1 tmp(&a);
|
||
|
}
|
||
|
|
||
|
struct RecordDynTypedVoidPointerTest {
|
||
|
struct RecordType {
|
||
|
int x; // expected-note{{uninitialized field 'static_cast<struct RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
|
||
|
int y; // expected-note{{uninitialized field 'static_cast<struct RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}}
|
||
|
};
|
||
|
|
||
|
void *vptr;
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}}
|
||
|
};
|
||
|
|
||
|
void fRecordDynTypedVoidPointerTest() {
|
||
|
RecordDynTypedVoidPointerTest::RecordType a;
|
||
|
RecordDynTypedVoidPointerTest tmp(&a);
|
||
|
}
|
||
|
|
||
|
struct NestedNonVoidDynTypedVoidPointerTest {
|
||
|
struct RecordType {
|
||
|
int x; // expected-note{{uninitialized field 'static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
|
||
|
int y; // expected-note{{uninitialized field 'static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}}
|
||
|
void *vptr; // expected-note{{uninitialized pointee 'static_cast<char *>(static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->vptr)'}}
|
||
|
};
|
||
|
|
||
|
void *vptr;
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) {
|
||
|
static_cast<RecordType *>(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void fNestedNonVoidDynTypedVoidPointerTest() {
|
||
|
NestedNonVoidDynTypedVoidPointerTest::RecordType a;
|
||
|
char c;
|
||
|
NestedNonVoidDynTypedVoidPointerTest tmp(&a, &c);
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Incomplete pointee tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
class IncompleteType;
|
||
|
|
||
|
struct IncompletePointeeTypeTest {
|
||
|
IncompleteType *pImpl; //no-crash
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
IncompletePointeeTypeTest(IncompleteType *A) : pImpl(A) {}
|
||
|
};
|
||
|
|
||
|
void fIncompletePointeeTypeTest(void *ptr) {
|
||
|
IncompletePointeeTypeTest(reinterpret_cast<IncompleteType *>(ptr));
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Function pointer tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct FunctionPointerWithDifferentDynTypeTest {
|
||
|
using Func1 = void *(*)();
|
||
|
using Func2 = int *(*)();
|
||
|
|
||
|
Func1 f; // no-crash
|
||
|
FunctionPointerWithDifferentDynTypeTest(Func2 f) : f((Func1)f) {}
|
||
|
};
|
||
|
|
||
|
// Note that there isn't a function calling the constructor of
|
||
|
// FunctionPointerWithDifferentDynTypeTest, because a crash could only be
|
||
|
// reproduced without it.
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Member pointer tests.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct UsefulFunctions {
|
||
|
int a, b;
|
||
|
|
||
|
void print() {}
|
||
|
void dump() {}
|
||
|
};
|
||
|
|
||
|
#ifdef PEDANTIC
|
||
|
struct PointerToMemberFunctionTest1 {
|
||
|
void (UsefulFunctions::*f)(void); // expected-note{{uninitialized field 'this->f'}}
|
||
|
PointerToMemberFunctionTest1() {}
|
||
|
};
|
||
|
|
||
|
void fPointerToMemberFunctionTest1() {
|
||
|
PointerToMemberFunctionTest1(); // expected-warning{{1 uninitialized field}}
|
||
|
}
|
||
|
|
||
|
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 {
|
||
|
int UsefulFunctions::*d; // expected-note{{uninitialized field 'this->d'}}
|
||
|
PointerToMemberDataTest1() {}
|
||
|
};
|
||
|
|
||
|
void fPointerToMemberDataTest1() {
|
||
|
PointerToMemberDataTest1(); // expected-warning{{1 uninitialized field}}
|
||
|
}
|
||
|
|
||
|
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());
|
||
|
}
|
||
|
|
||
|
struct RingListTest {
|
||
|
RingListTest *next; // no-crash
|
||
|
RingListTest() : next(this) {}
|
||
|
};
|
||
|
|
||
|
void fRingListTest() {
|
||
|
RingListTest();
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// 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);
|
||
|
}
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Tests for objects containing multiple references to the same object.
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
struct IntMultipleReferenceToSameObjectTest {
|
||
|
int *iptr; // expected-note{{uninitialized pointee 'this->iptr'}}
|
||
|
int &iref; // no-note, pointee of this->iref was already reported
|
||
|
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
IntMultipleReferenceToSameObjectTest(int *i) : iptr(i), iref(*i) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
void fIntMultipleReferenceToSameObjectTest() {
|
||
|
int a;
|
||
|
IntMultipleReferenceToSameObjectTest Test(&a);
|
||
|
}
|
||
|
|
||
|
struct IntReferenceWrapper1 {
|
||
|
int &a; // expected-note{{uninitialized pointee 'this->a'}}
|
||
|
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
IntReferenceWrapper1(int &a) : a(a) {} // expected-warning{{1 uninitialized field}}
|
||
|
};
|
||
|
|
||
|
struct IntReferenceWrapper2 {
|
||
|
int &a; // no-note, pointee of this->a was already reported
|
||
|
|
||
|
int dontGetFilteredByNonPedanticMode = 0;
|
||
|
|
||
|
IntReferenceWrapper2(int &a) : a(a) {} // no-warning
|
||
|
};
|
||
|
|
||
|
void fMultipleObjectsReferencingTheSameObjectTest() {
|
||
|
int a;
|
||
|
|
||
|
IntReferenceWrapper1 T1(a);
|
||
|
IntReferenceWrapper2 T2(a);
|
||
|
}
|