1 // RUN: %clangxx -frtti -fsanitize=null,vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false
2 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t rT
3 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t mT
4 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t fT
5 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t cT
6 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t rU
7 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t mU
8 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t fU
9 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t cU
10 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t rS
11 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t rV
12 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t oV
13 // RUN: %env_ubsan_opts=halt_on_error=1 %run %t zN
14 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --allow-unused-prefixes --check-prefix=CHECK-%os-MEMBER --strict-whitespace
15 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
16 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --allow-unused-prefixes --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
17 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --allow-unused-prefixes --check-prefix=CHECK-%os-MEMBER --strict-whitespace
18 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
19 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --allow-unused-prefixes --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
20 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --allow-unused-prefixes --check-prefix=CHECK-%os-OFFSET --strict-whitespace
21 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --allow-unused-prefixes --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
22 // RUN: %env_ubsan_opts=halt_on_error=1:print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --allow-unused-prefixes --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
23 // RUN: %env_ubsan_opts=halt_on_error=1 not %run %t nN 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMFUN --strict-whitespace
24 // RUN: %env_ubsan_opts=print_stacktrace=1 %run %t dT 2>&1 | FileCheck %s --check-prefix=CHECK-DYNAMIC --allow-unused-prefixes --check-prefix=CHECK-%os-DYNAMIC --strict-whitespace
25 
26 // RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
27 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t mS
28 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t fS
29 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t cS
30 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t mV
31 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t fV
32 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t cV
33 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t oU
34 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.supp"' %run %t dT
35 
36 // RUN: echo "vptr_check:S" > %t.loc-supp
37 // RUN: %env_ubsan_opts=halt_on_error=1:suppressions='"%t.loc-supp"' not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
38 
39 // REQUIRES: stable-runtime, cxxabi
40 // UNSUPPORTED: windows-msvc
41 // Suppressions file not pushed to the device.
42 // UNSUPPORTED: android
43 // Compilation error
44 // UNSUPPORTED: openbsd
45 // Compilation error
46 // UNSUPPORTED: freebsd
47 #include <new>
48 #include <typeinfo>
49 #include <assert.h>
50 #include <stdio.h>
51 
52 struct S {
SS53   S() : a(0) {}
54   ~S();
55   int a;
fS56   int f() { return 0; }
vS57   virtual int v() { return 0; }
58 };
59 
60 struct T : S {
TT61   T() : b(0) {}
62   int b;
gT63   int g() { return 0; }
vT64   virtual int v() { return 1; }
65 };
66 
vU67 struct U : S, T { virtual int v() { return 2; } };
68 
69 struct V : S {};
70 
71 namespace {
72   struct W {};
73 }
74 
75 T *p = 0;
76 
77 bool dtorCheck = false;
78 
79 volatile void *sink1, *sink2;
80 
81 int access_p(T *p, char type);
82 
~S()83 S::~S() {
84   if (dtorCheck)
85     access_p(p, '~');
86 }
87 
main(int argc,char ** argv)88 int main(int argc, char **argv) {
89   assert(argc > 1);
90   fprintf(stderr, "Test case: %s\n", argv[1]);
91   T t;
92   (void)t.a;
93   (void)t.b;
94   (void)t.f();
95   (void)t.g();
96   (void)t.v();
97   (void)t.S::v();
98 
99   U u;
100   (void)u.T::a;
101   (void)u.b;
102   (void)u.T::f();
103   (void)u.g();
104   (void)u.v();
105   (void)u.T::v();
106   (void)((T&)u).S::v();
107 
108   char Buffer[sizeof(U)] = {};
109   char TStorage[sizeof(T)];
110   // Allocate two dummy objects so that the real object
111   // is not on the boundary of mapped memory. Otherwise ubsan
112   // will not be able to describe the vptr in detail.
113   sink1 = new T;
114   sink2 = new U;
115   switch (argv[1][1]) {
116   case '0':
117     p = reinterpret_cast<T*>(Buffer);
118     break;
119   case 'S':
120     // Make sure p points to the memory chunk of sufficient size to prevent ASan
121     // reports about out-of-bounds access.
122     p = reinterpret_cast<T*>(new(TStorage) S);
123     break;
124   case 'T':
125     p = new T;
126     break;
127   case 'U':
128     p = new U;
129     break;
130   case 'V':
131     p = reinterpret_cast<T*>(new U);
132     break;
133   case 'N':
134     p = 0;
135     break;
136   }
137 
138   access_p(p, argv[1][0]);
139   return 0;
140 }
141 
access_p(T * p,char type)142 int access_p(T *p, char type) {
143   switch (type) {
144   case 'r':
145     // Binding a reference to storage of appropriate size and alignment is OK.
146     {T &r = *p;}
147     return 0;
148 
149   case 'x':
150     for (int i = 0; i < 2; i++) {
151       // Check that the first iteration ("S") succeeds, while the second ("V") fails.
152       p = reinterpret_cast<T*>((i == 0) ? new S : new V);
153       // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:10: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
154       // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
155       // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
156       // CHECK-LOC-SUPPRESS-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
157       // CHECK-LOC-SUPPRESS-NEXT: {{^              vptr for 'V'}}
158       p->g();
159     }
160     return 0;
161 
162   case 'm':
163     // 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'
164     // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
165     // CHECK-MEMBER-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
166     // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
167     // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
168     // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
169     return p->b;
170 
171     // CHECK-INVALID-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'
172     // CHECK-INVALID-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
173     // CHECK-INVALID-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
174     // CHECK-INVALID-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
175     // CHECK-INVALID-MEMBER-NEXT: {{^              invalid vptr}}
176     // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]]
177 
178   case 'f':
179     // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:15: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
180     // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
181     // CHECK-MEMFUN-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
182     // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
183     // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
184     // TODO: Add check for stacktrace here.
185     return p->g();
186 
187   case 'o':
188     // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:37: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
189     // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
190     // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
191     // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
192     // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
193     // CHECK-Linux-OFFSET: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
194     return reinterpret_cast<U*>(p)->v() - 2;
195 
196   case 'c':
197     // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:11: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
198     // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
199     // CHECK-DOWNCAST-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
200     // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
201     // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
202     // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
203     (void)static_cast<T*>(reinterpret_cast<S*>(p));
204     return 0;
205 
206   case 'n':
207     // CHECK-NULL-MEMFUN: vptr.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T'
208     return p->g();
209 
210   case 'd':
211     dtorCheck = true;
212     delete p;
213     dtorCheck = false;
214     return 0;
215   case '~':
216     // CHECK-DYNAMIC: vptr.cpp:[[@LINE+6]]:11: runtime error: dynamic operation on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
217     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
218     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
219     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
220     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
221     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
222     (void)dynamic_cast<V*>(p);
223     // CHECK-DYNAMIC: vptr.cpp:[[@LINE+6]]:11: runtime error: dynamic operation on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
224     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
225     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
226     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
227     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
228     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
229     (void)dynamic_cast<W*>(p);
230     try {
231       // CHECK-DYNAMIC: vptr.cpp:[[@LINE+6]]:13: runtime error: dynamic operation on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
232       // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
233       // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
234       // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
235       // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
236       // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
237       (void)dynamic_cast<V&>(*p);
238     } catch (std::bad_cast &) {}
239     // CHECK-DYNAMIC: vptr.cpp:[[@LINE+6]]:18: runtime error: dynamic operation on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
240     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
241     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
242     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
243     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
244     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
245     (void)typeid(*p);
246     return 0;
247 
248   case 'z':
249     (void)dynamic_cast<V*>(p);
250     try {
251       (void)typeid(*p);
252     } catch (std::bad_typeid &) {}
253     return 0;
254   }
255   return 0;
256 }
257