xref: /llvm-project/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr.cpp (revision d28c0fb186dad157daf00a8a43a34daa49593cda)
1 // RUN: %clangxx -frtti -fsanitize=null,vptr -fno-sanitize-memory-param-retval -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 -e "vptr_check:S\nvptr_check:T\nvptr_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: target={{.*windows-msvc.*}}
41 // Suppressions file not pushed to the device.
42 // UNSUPPORTED: android
43 // Compilation error
44 // UNSUPPORTED: target={{.*openbsd.*}}
45 // Compilation error
46 // UNSUPPORTED: target={{.*freebsd.*}}
47 // FIXME: For MinGW targets, the vptr tests do generally work, but Itanium
48 // demangling isn't done for the type names. The "(echo ..." line fails to
49 // be handled by the shell.
50 // XFAIL: target={{.*windows-gnu.*}}
51 #include <new>
52 #include <typeinfo>
53 #include <assert.h>
54 #include <stdio.h>
55 
56 struct S {
57   S() : a(0) {}
58   ~S();
59   int a;
60   int f() { return 0; }
61   virtual int v() { return 0; }
62 };
63 
64 struct T : S {
65   T() : b(0) {}
66   int b;
67   int g() { return 0; }
68   virtual int v() { return 1; }
69 };
70 
71 struct U : S, T { virtual int v() { return 2; } };
72 
73 struct V : S {};
74 
75 namespace {
76   struct W {};
77 }
78 
79 T *p = 0;
80 
81 bool dtorCheck = false;
82 
83 volatile void *sink1, *sink2;
84 
85 int access_p(T *p, char type);
86 
87 S::~S() {
88   if (dtorCheck)
89     access_p(p, '~');
90 }
91 
92 int main(int argc, char **argv) {
93   assert(argc > 1);
94   fprintf(stderr, "Test case: %s\n", argv[1]);
95   T t;
96   (void)t.a;
97   (void)t.b;
98   (void)t.f();
99   (void)t.g();
100   (void)t.v();
101   (void)t.S::v();
102 
103   U u;
104   (void)u.T::a;
105   (void)u.b;
106   (void)u.T::f();
107   (void)u.g();
108   (void)u.v();
109   (void)u.T::v();
110   (void)((T&)u).S::v();
111 
112   char Buffer[sizeof(U)] = {};
113   char TStorage[sizeof(T)];
114   // Allocate two dummy objects so that the real object
115   // is not on the boundary of mapped memory. Otherwise ubsan
116   // will not be able to describe the vptr in detail.
117   sink1 = new T;
118   sink2 = new U;
119   switch (argv[1][1]) {
120   case '0':
121     p = reinterpret_cast<T*>(Buffer);
122     break;
123   case 'S':
124     // Make sure p points to the memory chunk of sufficient size to prevent ASan
125     // reports about out-of-bounds access.
126     p = reinterpret_cast<T*>(new(TStorage) S);
127     break;
128   case 'T':
129     p = new T;
130     break;
131   case 'U':
132     p = new U;
133     break;
134   case 'V':
135     p = reinterpret_cast<T*>(new U);
136     break;
137   case 'N':
138     p = 0;
139     break;
140   }
141 
142   access_p(p, argv[1][0]);
143   return 0;
144 }
145 
146 int access_p(T *p, char type) {
147   switch (type) {
148   case 'r':
149     // Binding a reference to storage of appropriate size and alignment is OK.
150     {T &r = *p;}
151     return 0;
152 
153   case 'x':
154     for (int i = 0; i < 2; i++) {
155       // Check that the first iteration ("S") succeeds, while the second ("V") fails.
156       p = reinterpret_cast<T*>((i == 0) ? new S : new V);
157       // 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'
158       // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
159       // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
160       // CHECK-LOC-SUPPRESS-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
161       // CHECK-LOC-SUPPRESS-NEXT: {{^              vptr for 'V'}}
162       p->g();
163     }
164     return 0;
165 
166   case 'm':
167     // 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'
168     // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
169     // CHECK-MEMBER-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
170     // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
171     // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
172     // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
173     return p->b;
174 
175     // 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'
176     // CHECK-INVALID-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
177     // CHECK-INVALID-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
178     // CHECK-INVALID-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
179     // CHECK-INVALID-MEMBER-NEXT: {{^              invalid vptr}}
180     // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]]
181 
182   case 'f':
183     // 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'
184     // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
185     // CHECK-MEMFUN-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
186     // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
187     // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
188     // TODO: Add check for stacktrace here.
189     return p->g();
190 
191   case 'o':
192     // 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'
193     // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
194     // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
195     // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
196     // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
197     // CHECK-Linux-OFFSET: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
198     return reinterpret_cast<U*>(p)->v() - 2;
199 
200   case 'c':
201     // 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'
202     // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
203     // CHECK-DOWNCAST-NEXT: {{^  ?.. .. .. ..  ?.. .. .. ..  ?.. .. .. ..  ?}}
204     // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
205     // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
206     // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
207     (void)static_cast<T*>(reinterpret_cast<S*>(p));
208     return 0;
209 
210   case 'n':
211     // CHECK-NULL-MEMFUN: vptr.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T'
212     return p->g();
213 
214   case 'd':
215     dtorCheck = true;
216     delete p;
217     dtorCheck = false;
218     return 0;
219   case '~':
220     // 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'
221     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
222     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
223     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
224     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
225     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
226     (void)dynamic_cast<V*>(p);
227     // 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'
228     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
229     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
230     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
231     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
232     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
233     (void)dynamic_cast<W*>(p);
234     try {
235       // 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'
236       // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
237       // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
238       // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
239       // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
240       // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
241       (void)dynamic_cast<V&>(*p);
242     } catch (std::bad_cast &) {}
243     // 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'
244     // CHECK-DYNAMIC-NEXT: [[PTR]]: note: object is of type 'S'
245     // CHECK-DYNAMIC-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
246     // CHECK-DYNAMIC-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
247     // CHECK-DYNAMIC-NEXT: {{^              vptr for}} 'S'
248     // CHECK-Linux-DYNAMIC: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
249     (void)typeid(*p);
250     return 0;
251 
252   case 'z':
253     (void)dynamic_cast<V*>(p);
254     try {
255       (void)typeid(*p);
256     } catch (std::bad_typeid &) {}
257     return 0;
258   }
259   return 0;
260 }
261