1 | // RUN: %clangxx_scudo -std=c++1z -faligned-allocation %s -o %t |
2 | // RUN: %run %t valid 2>&1 |
3 | // RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 |
4 | // RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t invalid 2>&1 | FileCheck %s |
5 | |
6 | // Tests that the C++17 aligned new/delete operators are working as expected. |
7 | // Currently we do not check the consistency of the alignment on deallocation, |
8 | // so this just tests that the APIs work. |
9 | |
10 | #include <assert.h> |
11 | #include <stdint.h> |
12 | #include <stdio.h> |
13 | #include <string.h> |
14 | |
15 | // Define all new/delete to not depend on the version provided by the platform. |
16 | |
17 | namespace std { |
18 | struct nothrow_t {}; |
19 | static const nothrow_t nothrow; |
20 | enum class align_val_t : size_t {}; |
21 | } // namespace std |
22 | |
23 | void *operator new(size_t); |
24 | void *operator new[](size_t); |
25 | void *operator new(size_t, std::nothrow_t const &); |
26 | void *operator new[](size_t, std::nothrow_t const &); |
27 | void *operator new(size_t, std::align_val_t); |
28 | void *operator new[](size_t, std::align_val_t); |
29 | void *operator new(size_t, std::align_val_t, std::nothrow_t const &); |
30 | void *operator new[](size_t, std::align_val_t, std::nothrow_t const &); |
31 | |
32 | void operator delete(void *) throw(); |
33 | void operator delete[](void *) throw(); |
34 | void operator delete(void *, std::nothrow_t const &); |
35 | void operator delete[](void *, std::nothrow_t const &); |
36 | void operator delete(void *, size_t) throw(); |
37 | void operator delete[](void *, size_t) throw(); |
38 | void operator delete(void *, std::align_val_t) throw(); |
39 | void operator delete[](void *, std::align_val_t) throw(); |
40 | void operator delete(void *, std::align_val_t, std::nothrow_t const &); |
41 | void operator delete[](void *, std::align_val_t, std::nothrow_t const &); |
42 | void operator delete(void *, size_t, std::align_val_t) throw(); |
43 | void operator delete[](void *, size_t, std::align_val_t) throw(); |
44 | |
45 | template <typename T> |
46 | inline T *break_optimization(T *arg) { |
47 | __asm__ __volatile__("" |
48 | : |
49 | : "r" (arg) |
50 | : "memory" ); |
51 | return arg; |
52 | } |
53 | |
54 | struct S12 { |
55 | int a, b, c; |
56 | }; |
57 | struct alignas(128) S12_128 { |
58 | int a, b, c; |
59 | }; |
60 | struct alignas(256) S12_256 { |
61 | int a, b, c; |
62 | }; |
63 | struct alignas(512) S1024_512 { |
64 | char a[1024]; |
65 | }; |
66 | struct alignas(1024) S1024_1024 { |
67 | char a[1024]; |
68 | }; |
69 | |
70 | int main(int argc, char **argv) { |
71 | assert(argc == 2); |
72 | |
73 | if (!strcmp(s1: argv[1], s2: "valid" )) { |
74 | // Standard use case. |
75 | delete break_optimization(arg: new S12); |
76 | delete break_optimization(arg: new S12_128); |
77 | delete[] break_optimization(arg: new S12_128[4]); |
78 | delete break_optimization(arg: new S12_256); |
79 | delete break_optimization(arg: new S1024_512); |
80 | delete[] break_optimization(arg: new S1024_512[4]); |
81 | delete break_optimization(arg: new S1024_1024); |
82 | |
83 | // Call directly the aligned versions of the operators. |
84 | const size_t alignment = 1U << 8; |
85 | void *p = operator new(1, static_cast<std::align_val_t>(alignment)); |
86 | assert((reinterpret_cast<uintptr_t>(p) & (alignment - 1)) == 0); |
87 | operator delete(p, static_cast<std::align_val_t>(alignment)); |
88 | } |
89 | if (!strcmp(s1: argv[1], s2: "invalid" )) { |
90 | // Alignment must be a power of 2. |
91 | const size_t alignment = (1U << 8) - 1; |
92 | void *p = operator new(1, static_cast<std::align_val_t>(alignment), |
93 | std::nothrow); |
94 | // CHECK: Scudo ERROR: invalid allocation alignment |
95 | assert(!p); |
96 | } |
97 | |
98 | return 0; |
99 | } |
100 | |