[UBSan] Add the ability to dump call stacks to -fsanitize=vptr
[blocksruntime.git] / test / ubsan / TestCases / TypeCheck / vptr.cpp
blob68ca6926df41bec6509903f6193bbdf8789ccde2
1 // RUN: %clangxx -fsanitize=vptr -g %s -O3 -o %t
2 // RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
3 // RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
4 // RUN: %run %t rS && %run %t rV && %run %t oV
5 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
6 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
7 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
8 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
9 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
10 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
11 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
12 // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
14 // FIXME: This test produces linker errors on Darwin.
15 // XFAIL: darwin
17 struct S {
18 S() : a(0) {}
19 ~S() {}
20 int a;
21 int f() { return 0; }
22 virtual int v() { return 0; }
25 struct T : S {
26 T() : b(0) {}
27 int b;
28 int g() { return 0; }
29 virtual int v() { return 1; }
32 struct U : S, T { virtual int v() { return 2; } };
34 T *p = 0; // Make p global so that lsan does not complain.
36 int main(int, char **argv) {
37 T t;
38 (void)t.a;
39 (void)t.b;
40 (void)t.f();
41 (void)t.g();
42 (void)t.v();
43 (void)t.S::v();
45 U u;
46 (void)u.T::a;
47 (void)u.b;
48 (void)u.T::f();
49 (void)u.g();
50 (void)u.v();
51 (void)u.T::v();
52 (void)((T&)u).S::v();
54 char Buffer[sizeof(U)] = {};
55 switch (argv[1][1]) {
56 case '0':
57 p = reinterpret_cast<T*>(Buffer);
58 break;
59 case 'S':
60 p = reinterpret_cast<T*>(new S);
61 break;
62 case 'T':
63 p = new T;
64 break;
65 case 'U':
66 p = new U;
67 break;
68 case 'V':
69 p = reinterpret_cast<T*>(new U);
70 break;
73 switch (argv[1][0]) {
74 case 'r':
75 // Binding a reference to storage of appropriate size and alignment is OK.
76 {T &r = *p;}
77 break;
79 case 'm':
80 // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
81 // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
82 // CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
83 // CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
84 // CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]]
85 // CHECK-MEMBER-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
86 return p->b;
88 // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
89 // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
90 // CHECK-NULL-MEMBER-NEXT: {{^ ?.. .. .. .. ?00 00 00 00 ?00 00 00 00 ?}}
91 // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
92 // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}}
93 // CHECK-NULL-MEMBER-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE-7]]
95 case 'f':
96 // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
97 // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
98 // CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
99 // CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
100 // CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]]
101 // TODO: Add check for stacktrace here.
102 return p->g();
104 case 'o':
105 // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
106 // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
107 // CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }}
108 // CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
109 // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]
110 // CHECK-OFFSET-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
111 return reinterpret_cast<U*>(p)->v() - 2;
113 case 'c':
114 // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
115 // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
116 // CHECK-DOWNCAST-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
117 // CHECK-DOWNCAST-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
118 // CHECK-DOWNCAST-NEXT: {{^ vptr for}} [[DYN_TYPE]]
119 // CHECK-DOWNCAST-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
120 static_cast<T*>(reinterpret_cast<S*>(p));
121 return 0;