diff options
author | Kristof Umann <dkszelethus@gmail.com> | 2018-06-18 11:50:17 +0000 |
---|---|---|
committer | Kristof Umann <dkszelethus@gmail.com> | 2018-06-18 11:50:17 +0000 |
commit | 30f086565c78f986cd462966c9f656331f2a5655 (patch) | |
tree | 92095dd8ad24e43d331e3b8e4c987a56b949d959 /clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp | |
parent | 99a58320167d06771659f8da3cd3f2b70b78395f (diff) | |
download | bcm5719-llvm-30f086565c78f986cd462966c9f656331f2a5655.tar.gz bcm5719-llvm-30f086565c78f986cd462966c9f656331f2a5655.zip |
[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
llvm-svn: 334935
Diffstat (limited to 'clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp')
-rw-r--r-- | clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp | 699 |
1 files changed, 699 insertions, 0 deletions
diff --git a/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp b/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp new file mode 100644 index 00000000000..e6c0b91a62e --- /dev/null +++ b/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp @@ -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); +} |