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