2017-10-05 16:43:32 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
|
[analyzer] Fix a crash during C++17 aggregate construction of base objects.
Since C++17, classes that have base classes can potentially be initialized as
aggregates. Trying to construct such objects through brace initialization was
causing the analyzer to crash when the base class has a non-trivial constructor,
while figuring target region for the base class constructor, because the parent
stack frame didn't contain the constructor of the subclass, because there is
no constructor for subclass, merely aggregate initialization.
This patch avoids the crash, but doesn't provide the actually correct region
for the constructor, which still remains to be fixed. Instead, construction
goes into a fake temporary region which would be immediately discarded. Similar
extremely conservative approach is used for other cases in which the logic for
finding the target region is not yet implemented, including aggregate
initialization with fields instead of base-regions (which is not C++17-specific
but also never worked, just didn't crash).
Differential revision: https://reviews.llvm.org/D40841
rdar://problem/35441058
llvm-svn: 321128
2017-12-20 08:40:38 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++17 -DCPLUSPLUS17 -verify %s
|
2018-01-25 05:24:10 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify %s
|
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++17 -DCPLUSPLUS17 -DTEST_INLINABLE_ALLOCATORS -verify %s
|
2012-05-17 00:01:10 +08:00
|
|
|
|
|
|
|
void clang_analyzer_eval(bool);
|
2010-11-16 15:52:17 +08:00
|
|
|
|
2017-10-05 16:43:32 +08:00
|
|
|
#include "Inputs/system-header-simulator-cxx.h"
|
|
|
|
|
2010-11-16 15:52:17 +08:00
|
|
|
class A {
|
|
|
|
int x;
|
|
|
|
public:
|
|
|
|
A();
|
|
|
|
};
|
|
|
|
|
|
|
|
A::A() : x(0) {
|
2012-05-17 00:01:10 +08:00
|
|
|
clang_analyzer_eval(x == 0); // expected-warning{{TRUE}}
|
2010-11-16 15:52:17 +08:00
|
|
|
}
|
2012-07-27 04:04:21 +08:00
|
|
|
|
|
|
|
|
|
|
|
class DirectMember {
|
|
|
|
int x;
|
|
|
|
public:
|
|
|
|
DirectMember(int value) : x(value) {}
|
|
|
|
|
|
|
|
int getX() { return x; }
|
|
|
|
};
|
|
|
|
|
|
|
|
void testDirectMember() {
|
|
|
|
DirectMember obj(3);
|
|
|
|
clang_analyzer_eval(obj.getX() == 3); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class IndirectMember {
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
};
|
|
|
|
public:
|
|
|
|
IndirectMember(int value) : x(value) {}
|
|
|
|
|
|
|
|
int getX() { return x; }
|
|
|
|
};
|
|
|
|
|
|
|
|
void testIndirectMember() {
|
|
|
|
IndirectMember obj(3);
|
|
|
|
clang_analyzer_eval(obj.getX() == 3); // expected-warning{{TRUE}}
|
|
|
|
}
|
2012-08-03 05:33:42 +08:00
|
|
|
|
|
|
|
|
2012-08-04 07:31:15 +08:00
|
|
|
struct DelegatingConstructor {
|
|
|
|
int x;
|
|
|
|
DelegatingConstructor(int y) { x = y; }
|
|
|
|
DelegatingConstructor() : DelegatingConstructor(42) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void testDelegatingConstructor() {
|
|
|
|
DelegatingConstructor obj;
|
|
|
|
clang_analyzer_eval(obj.x == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-03 05:33:42 +08:00
|
|
|
struct RefWrapper {
|
|
|
|
RefWrapper(int *p) : x(*p) {}
|
|
|
|
RefWrapper(int &r) : x(r) {}
|
|
|
|
int &x;
|
|
|
|
};
|
|
|
|
|
|
|
|
void testReferenceMember() {
|
|
|
|
int *p = 0;
|
2012-09-01 01:06:49 +08:00
|
|
|
RefWrapper X(p); // expected-warning@-7 {{Dereference of null pointer}}
|
2012-08-03 05:33:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void testReferenceMember2() {
|
|
|
|
int *p = 0;
|
2013-03-07 11:02:36 +08:00
|
|
|
RefWrapper X(*p); // expected-warning {{Forming reference to null pointer}}
|
2012-08-03 05:33:42 +08:00
|
|
|
}
|
2012-08-25 09:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
extern "C" char *strdup(const char *);
|
|
|
|
|
|
|
|
class StringWrapper {
|
|
|
|
char *str;
|
|
|
|
public:
|
|
|
|
StringWrapper(const char *input) : str(strdup(input)) {} // no-warning
|
|
|
|
};
|
2013-01-26 11:16:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
// PR15070 - Constructing a type containing a non-POD array mistakenly
|
|
|
|
// tried to perform a bind instead of relying on the CXXConstructExpr,
|
|
|
|
// which caused a cast<> failure in RegionStore.
|
|
|
|
namespace DefaultConstructorWithCleanups {
|
|
|
|
class Element {
|
|
|
|
public:
|
|
|
|
int value;
|
|
|
|
|
|
|
|
class Helper {
|
|
|
|
public:
|
|
|
|
~Helper();
|
|
|
|
};
|
|
|
|
Element(Helper h = Helper());
|
|
|
|
};
|
|
|
|
class Wrapper {
|
|
|
|
public:
|
|
|
|
Element arr[2];
|
|
|
|
|
|
|
|
Wrapper();
|
|
|
|
};
|
|
|
|
|
|
|
|
Wrapper::Wrapper() /* initializers synthesized */ {}
|
|
|
|
|
|
|
|
int test() {
|
|
|
|
Wrapper w;
|
|
|
|
return w.arr[0].value; // no-warning
|
|
|
|
}
|
|
|
|
}
|
2013-07-18 01:16:42 +08:00
|
|
|
|
|
|
|
namespace DefaultMemberInitializers {
|
|
|
|
struct Wrapper {
|
|
|
|
int value = 42;
|
|
|
|
|
|
|
|
Wrapper() {}
|
|
|
|
Wrapper(int x) : value(x) {}
|
|
|
|
Wrapper(bool) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void test() {
|
|
|
|
Wrapper w1;
|
|
|
|
clang_analyzer_eval(w1.value == 42); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
Wrapper w2(50);
|
|
|
|
clang_analyzer_eval(w2.value == 50); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
Wrapper w3(false);
|
|
|
|
clang_analyzer_eval(w3.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StringWrapper {
|
|
|
|
const char s[4] = "abc";
|
|
|
|
const char *p = "xyz";
|
|
|
|
|
|
|
|
StringWrapper(bool) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void testString() {
|
|
|
|
StringWrapper w(true);
|
|
|
|
clang_analyzer_eval(w.s[1] == 'b'); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(w.p[1] == 'y'); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
}
|
2015-12-17 08:28:33 +08:00
|
|
|
|
|
|
|
namespace ReferenceInitialization {
|
|
|
|
struct OtherStruct {
|
|
|
|
OtherStruct(int i);
|
|
|
|
~OtherStruct();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct MyStruct {
|
|
|
|
MyStruct(int i);
|
|
|
|
MyStruct(OtherStruct os);
|
|
|
|
|
|
|
|
void method() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
void referenceInitializeLocal() {
|
|
|
|
const MyStruct &myStruct(5);
|
|
|
|
myStruct.method(); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void referenceInitializeMultipleLocals() {
|
|
|
|
const MyStruct &myStruct1(5), myStruct2(5), &myStruct3(5);
|
|
|
|
myStruct1.method(); // no-warning
|
|
|
|
myStruct2.method(); // no-warning
|
|
|
|
myStruct3.method(); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void referenceInitializeLocalWithCleanup() {
|
|
|
|
const MyStruct &myStruct(OtherStruct(5));
|
|
|
|
myStruct.method(); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
struct HasMyStruct {
|
|
|
|
const MyStruct &ms; // expected-note {{reference member declared here}}
|
|
|
|
const MyStruct &msWithCleanups; // expected-note {{reference member declared here}}
|
|
|
|
|
|
|
|
// clang's Sema issues a warning when binding a reference member to a
|
|
|
|
// temporary value.
|
|
|
|
HasMyStruct() : ms(5), msWithCleanups(OtherStruct(5)) {
|
|
|
|
// expected-warning@-1 {{binding reference member 'ms' to a temporary value}}
|
|
|
|
// expected-warning@-2 {{binding reference member 'msWithCleanups' to a temporary value}}
|
|
|
|
|
|
|
|
// At this point the members are not garbage so we should not expect an
|
|
|
|
// analyzer warning here even though binding a reference member
|
|
|
|
// to a member is a terrible idea.
|
|
|
|
ms.method(); // no-warning
|
|
|
|
msWithCleanups.method(); // no-warning
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void referenceInitializeField() {
|
|
|
|
HasMyStruct hms;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2017-01-12 17:46:16 +08:00
|
|
|
|
|
|
|
namespace PR31592 {
|
|
|
|
struct C {
|
|
|
|
C() : f("}") { } // no-crash
|
|
|
|
const char(&f)[2];
|
|
|
|
};
|
|
|
|
}
|
2017-10-05 16:43:32 +08:00
|
|
|
|
|
|
|
namespace CXX_initializer_lists {
|
|
|
|
struct C {
|
|
|
|
C(std::initializer_list<int *> list);
|
|
|
|
};
|
2017-11-28 01:37:09 +08:00
|
|
|
void testPointerEscapeIntoLists() {
|
2017-10-05 16:43:32 +08:00
|
|
|
C empty{}; // no-crash
|
|
|
|
|
|
|
|
// Do not warn that 'x' leaks. It might have been deleted by
|
|
|
|
// the destructor of 'c'.
|
|
|
|
int *x = new int;
|
|
|
|
C c{x}; // no-warning
|
|
|
|
}
|
2017-11-28 01:37:09 +08:00
|
|
|
|
|
|
|
void testPassListsWithExplicitConstructors() {
|
|
|
|
(void)(std::initializer_list<int>){12}; // no-crash
|
|
|
|
}
|
2017-10-05 16:43:32 +08:00
|
|
|
}
|
[analyzer] Fix a crash during C++17 aggregate construction of base objects.
Since C++17, classes that have base classes can potentially be initialized as
aggregates. Trying to construct such objects through brace initialization was
causing the analyzer to crash when the base class has a non-trivial constructor,
while figuring target region for the base class constructor, because the parent
stack frame didn't contain the constructor of the subclass, because there is
no constructor for subclass, merely aggregate initialization.
This patch avoids the crash, but doesn't provide the actually correct region
for the constructor, which still remains to be fixed. Instead, construction
goes into a fake temporary region which would be immediately discarded. Similar
extremely conservative approach is used for other cases in which the logic for
finding the target region is not yet implemented, including aggregate
initialization with fields instead of base-regions (which is not C++17-specific
but also never worked, just didn't crash).
Differential revision: https://reviews.llvm.org/D40841
rdar://problem/35441058
llvm-svn: 321128
2017-12-20 08:40:38 +08:00
|
|
|
|
|
|
|
namespace CXX17_aggregate_construction {
|
|
|
|
struct A {
|
|
|
|
A();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B: public A {
|
|
|
|
};
|
|
|
|
|
|
|
|
struct C: public B {
|
|
|
|
};
|
|
|
|
|
|
|
|
struct D: public virtual A {
|
|
|
|
};
|
|
|
|
|
|
|
|
// In C++17, classes B and C are aggregates, so they will be constructed
|
|
|
|
// without actually calling their trivial constructor. Used to crash.
|
|
|
|
void foo() {
|
|
|
|
B b = {}; // no-crash
|
|
|
|
const B &bl = {}; // no-crash
|
|
|
|
B &&br = {}; // no-crash
|
|
|
|
|
|
|
|
C c = {}; // no-crash
|
|
|
|
const C &cl = {}; // no-crash
|
|
|
|
C &&cr = {}; // no-crash
|
|
|
|
|
|
|
|
D d = {}; // no-crash
|
|
|
|
|
|
|
|
#ifdef CPLUSPLUS17
|
|
|
|
C cd = {{}}; // no-crash
|
|
|
|
const C &cdl = {{}}; // no-crash
|
|
|
|
C &&cdr = {{}}; // no-crash
|
|
|
|
|
|
|
|
const B &bll = {{}}; // no-crash
|
|
|
|
const B &bcl = C({{}}); // no-crash
|
|
|
|
B &&bcr = C({{}}); // no-crash
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|