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