1*673dc3d4SNico Weber // RUN: %clangxx_asan -fsized-deallocation -O0 %s -o %t
2*673dc3d4SNico Weber // RUN:                                                                  not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
3*673dc3d4SNico Weber // RUN: %env_asan_opts=new_delete_type_mismatch=1 not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
4*673dc3d4SNico Weber // RUN:                                                                  not %run %t array  2>&1 | FileCheck %s -check-prefix=ARRAY
5*673dc3d4SNico Weber // RUN: %env_asan_opts=new_delete_type_mismatch=1 not %run %t array  2>&1 | FileCheck %s -check-prefix=ARRAY
6*673dc3d4SNico Weber // RUN: %env_asan_opts=new_delete_type_mismatch=0     %run %t scalar
7*673dc3d4SNico Weber // RUN: %env_asan_opts=new_delete_type_mismatch=0     %run %t array
8*673dc3d4SNico Weber 
9*673dc3d4SNico Weber #include <new>
10*673dc3d4SNico Weber #include <stdio.h>
11*673dc3d4SNico Weber #include <string>
12*673dc3d4SNico Weber 
break_optimization(void * arg)13*673dc3d4SNico Weber inline void break_optimization(void *arg) {
14*673dc3d4SNico Weber   __asm__ __volatile__("" : : "r" (arg) : "memory");
15*673dc3d4SNico Weber }
16*673dc3d4SNico Weber 
17*673dc3d4SNico Weber struct S12 {
18*673dc3d4SNico Weber   int a, b, c;
19*673dc3d4SNico Weber };
20*673dc3d4SNico Weber 
21*673dc3d4SNico Weber struct S20 {
22*673dc3d4SNico Weber   int a, b, c, d, e;
23*673dc3d4SNico Weber };
24*673dc3d4SNico Weber 
25*673dc3d4SNico Weber struct D1 {
26*673dc3d4SNico Weber   int a, b, c;
~D1D127*673dc3d4SNico Weber   ~D1() { fprintf(stderr, "D1::~D1\n"); }
28*673dc3d4SNico Weber };
29*673dc3d4SNico Weber 
30*673dc3d4SNico Weber struct D2 {
31*673dc3d4SNico Weber   int a, b, c, d, e;
~D2D232*673dc3d4SNico Weber   ~D2() { fprintf(stderr, "D2::~D2\n"); }
33*673dc3d4SNico Weber };
34*673dc3d4SNico Weber 
Del12(S12 * x)35*673dc3d4SNico Weber void Del12(S12 *x) {
36*673dc3d4SNico Weber   break_optimization(x);
37*673dc3d4SNico Weber   delete x;
38*673dc3d4SNico Weber }
Del12NoThrow(S12 * x)39*673dc3d4SNico Weber void Del12NoThrow(S12 *x) {
40*673dc3d4SNico Weber   break_optimization(x);
41*673dc3d4SNico Weber   operator delete(x, std::nothrow);
42*673dc3d4SNico Weber }
Del12Ar(S12 * x)43*673dc3d4SNico Weber void Del12Ar(S12 *x) {
44*673dc3d4SNico Weber   break_optimization(x);
45*673dc3d4SNico Weber   delete [] x;
46*673dc3d4SNico Weber }
Del12ArNoThrow(S12 * x)47*673dc3d4SNico Weber void Del12ArNoThrow(S12 *x) {
48*673dc3d4SNico Weber   break_optimization(x);
49*673dc3d4SNico Weber   operator delete[](x, std::nothrow);
50*673dc3d4SNico Weber }
51*673dc3d4SNico Weber 
main(int argc,char ** argv)52*673dc3d4SNico Weber int main(int argc, char **argv) {
53*673dc3d4SNico Weber   if (argc != 2) return 1;
54*673dc3d4SNico Weber   std::string flag = argv[1];
55*673dc3d4SNico Weber   // These are correct.
56*673dc3d4SNico Weber   Del12(new S12);
57*673dc3d4SNico Weber   Del12NoThrow(new S12);
58*673dc3d4SNico Weber   Del12Ar(new S12[100]);
59*673dc3d4SNico Weber   Del12ArNoThrow(new S12[100]);
60*673dc3d4SNico Weber 
61*673dc3d4SNico Weber   // Here we pass wrong type of pointer to delete,
62*673dc3d4SNico Weber   // but [] and nothrow variants of delete are not sized.
63*673dc3d4SNico Weber   Del12Ar(reinterpret_cast<S12*>(new S20[100]));
64*673dc3d4SNico Weber   Del12NoThrow(reinterpret_cast<S12*>(new S20));
65*673dc3d4SNico Weber   Del12ArNoThrow(reinterpret_cast<S12*>(new S20[100]));
66*673dc3d4SNico Weber   fprintf(stderr, "OK SO FAR\n");
67*673dc3d4SNico Weber   // SCALAR: OK SO FAR
68*673dc3d4SNico Weber   // ARRAY: OK SO FAR
69*673dc3d4SNico Weber   if (flag == "scalar") {
70*673dc3d4SNico Weber     // Here asan should bark as we are passing a wrong type of pointer
71*673dc3d4SNico Weber     // to sized delete.
72*673dc3d4SNico Weber     Del12(reinterpret_cast<S12*>(new S20));
73*673dc3d4SNico Weber     // SCALAR: AddressSanitizer: new-delete-type-mismatch
74*673dc3d4SNico Weber     // SCALAR:  object passed to delete has wrong type:
75*673dc3d4SNico Weber     // SCALAR:  size of the allocated type:   20 bytes;
76*673dc3d4SNico Weber     // SCALAR:  size of the deallocated type: 12 bytes.
77*673dc3d4SNico Weber     // SCALAR: is located 0 bytes inside of 20-byte region
78*673dc3d4SNico Weber     // SCALAR: SUMMARY: AddressSanitizer: new-delete-type-mismatch
79*673dc3d4SNico Weber   } else if (flag == "array") {
80*673dc3d4SNico Weber     D1 *d1 = reinterpret_cast<D1*>(new D2[10]);
81*673dc3d4SNico Weber     break_optimization(d1);
82*673dc3d4SNico Weber     delete [] d1;
83*673dc3d4SNico Weber     // ARRAY-NOT: D2::~D2
84*673dc3d4SNico Weber     // ARRAY: D1::~D1
85*673dc3d4SNico Weber     // ARRAY: AddressSanitizer: new-delete-type-mismatch
86*673dc3d4SNico Weber     // ARRAY:  size of the allocated type:   20{{4|8}} bytes;
87*673dc3d4SNico Weber     // ARRAY:  size of the deallocated type: 12{{4|8}} bytes.
88*673dc3d4SNico Weber   }
89*673dc3d4SNico Weber }
90