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