blob: 4a1fa8d54b18b8c75d40f16afc3ec3104b50def6 [file] [log] [blame]
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -07001// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t
Stephen Hines2d1fdb22014-05-28 23:58:16 -07002// 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
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -08005// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
6// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
7// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
8// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
9// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
10// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
11// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --check-prefix=CHECK-%os-OFFSET --strict-whitespace
12// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
Stephen Hines2d1fdb22014-05-28 23:58:16 -070013
Stephen Hines6d186232014-11-26 17:56:19 -080014// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080015// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mS
16// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fS
17// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cS
18// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mV
19// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fV
20// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cV
21// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t oU
Stephen Hines6d186232014-11-26 17:56:19 -080022
23// RUN: echo "vptr_check:S" > %t.loc-supp
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080024// RUN: %env_ubsan_opts=suppressions='"%t.loc-supp"' not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
Stephen Hines6d186232014-11-26 17:56:19 -080025
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080026// REQUIRES: stable-runtime, cxxabi
Stephen Hines86277eb2015-03-23 12:06:32 -070027#include <new>
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -070028#include <assert.h>
29#include <stdio.h>
Stephen Hines2d1fdb22014-05-28 23:58:16 -070030
31struct S {
32 S() : a(0) {}
33 ~S() {}
34 int a;
35 int f() { return 0; }
36 virtual int v() { return 0; }
37};
38
39struct T : S {
40 T() : b(0) {}
41 int b;
42 int g() { return 0; }
43 virtual int v() { return 1; }
44};
45
Stephen Hines86277eb2015-03-23 12:06:32 -070046struct U : S, T { virtual int v() { return 2; } };
Stephen Hines2d1fdb22014-05-28 23:58:16 -070047
Stephen Hines6d186232014-11-26 17:56:19 -080048struct V : S {};
49
50// Make p global so that lsan does not complain.
51T *p = 0;
52
53int access_p(T *p, char type);
Stephen Hines2d1fdb22014-05-28 23:58:16 -070054
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -070055int main(int argc, char **argv) {
56 assert(argc > 1);
57 fprintf(stderr, "Test case: %s\n", argv[1]);
Stephen Hines2d1fdb22014-05-28 23:58:16 -070058 T t;
59 (void)t.a;
60 (void)t.b;
61 (void)t.f();
62 (void)t.g();
63 (void)t.v();
64 (void)t.S::v();
65
66 U u;
67 (void)u.T::a;
68 (void)u.b;
69 (void)u.T::f();
70 (void)u.g();
71 (void)u.v();
72 (void)u.T::v();
73 (void)((T&)u).S::v();
74
75 char Buffer[sizeof(U)] = {};
Stephen Hines86277eb2015-03-23 12:06:32 -070076 char TStorage[sizeof(T)];
Stephen Hines2d1fdb22014-05-28 23:58:16 -070077 switch (argv[1][1]) {
78 case '0':
79 p = reinterpret_cast<T*>(Buffer);
80 break;
81 case 'S':
Stephen Hines86277eb2015-03-23 12:06:32 -070082 // Make sure p points to the memory chunk of sufficient size to prevent ASan
83 // reports about out-of-bounds access.
84 p = reinterpret_cast<T*>(new(TStorage) S);
Stephen Hines2d1fdb22014-05-28 23:58:16 -070085 break;
86 case 'T':
87 p = new T;
88 break;
89 case 'U':
90 p = new U;
91 break;
92 case 'V':
93 p = reinterpret_cast<T*>(new U);
94 break;
95 }
96
Stephen Hines6d186232014-11-26 17:56:19 -080097 access_p(p, argv[1][0]);
98 return 0;
99}
100
101int access_p(T *p, char type) {
102 switch (type) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700103 case 'r':
104 // Binding a reference to storage of appropriate size and alignment is OK.
105 {T &r = *p;}
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700106 return 0;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700107
Stephen Hines6d186232014-11-26 17:56:19 -0800108 case 'x':
109 for (int i = 0; i < 2; i++) {
110 // Check that the first iteration ("S") succeeds, while the second ("V") fails.
111 p = reinterpret_cast<T*>((i == 0) ? new S : new V);
112 // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:7: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
113 // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
114 // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
115 // CHECK-LOC-SUPPRESS-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
116 // CHECK-LOC-SUPPRESS-NEXT: {{^ vptr for 'V'}}
117 p->g();
118 }
119 return 0;
120
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700121 case 'm':
Stephen Hines6d186232014-11-26 17:56:19 -0800122 // 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'
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700123 // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
124 // CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
125 // CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
126 // CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]]
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700127 // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700128 return p->b;
129
130 // 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'
131 // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
132 // CHECK-NULL-MEMBER-NEXT: {{^ ?.. .. .. .. ?00 00 00 00 ?00 00 00 00 ?}}
133 // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
134 // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}}
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700135 // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]]
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700136
137 case 'f':
Stephen Hines6d186232014-11-26 17:56:19 -0800138 // 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'
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700139 // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
140 // CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
141 // CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
142 // CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]]
Stephen Hines6d186232014-11-26 17:56:19 -0800143 // TODO: Add check for stacktrace here.
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700144 return p->g();
145
146 case 'o':
Stephen Hines6d186232014-11-26 17:56:19 -0800147 // 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'
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700148 // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
149 // CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }}
150 // CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
151 // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700152 // CHECK-Linux-OFFSET: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700153 return reinterpret_cast<U*>(p)->v() - 2;
154
155 case 'c':
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700156 // 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'
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700157 // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
158 // CHECK-DOWNCAST-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
159 // CHECK-DOWNCAST-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
160 // CHECK-DOWNCAST-NEXT: {{^ vptr for}} [[DYN_TYPE]]
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700161 // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
162 (void)static_cast<T*>(reinterpret_cast<S*>(p));
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700163 return 0;
164 }
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700165 return 0;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700166}