1 | //===-- memprof_interceptors.cpp -----------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of MemProfiler, a memory profiler. |
10 | // |
11 | // Interceptors for operators new and delete. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "memprof_allocator.h" |
15 | #include "memprof_internal.h" |
16 | #include "memprof_stack.h" |
17 | #include "sanitizer_common/sanitizer_allocator_report.h" |
18 | |
19 | #include "interception/interception.h" |
20 | |
21 | #include <stddef.h> |
22 | |
23 | #define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE |
24 | |
25 | using namespace __memprof; |
26 | |
27 | // Fake std::nothrow_t and std::align_val_t to avoid including <new>. |
28 | namespace std { |
29 | struct nothrow_t {}; |
30 | enum class align_val_t : size_t {}; |
31 | } // namespace std |
32 | |
33 | #define OPERATOR_NEW_BODY(type, nothrow) \ |
34 | GET_STACK_TRACE_MALLOC; \ |
35 | void *res = memprof_memalign(0, size, &stack, type); \ |
36 | if (!nothrow && UNLIKELY(!res)) \ |
37 | ReportOutOfMemory(size, &stack); \ |
38 | return res; |
39 | #define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ |
40 | GET_STACK_TRACE_MALLOC; \ |
41 | void *res = memprof_memalign((uptr)align, size, &stack, type); \ |
42 | if (!nothrow && UNLIKELY(!res)) \ |
43 | ReportOutOfMemory(size, &stack); \ |
44 | return res; |
45 | |
46 | CXX_OPERATOR_ATTRIBUTE |
47 | void *operator new(size_t size) { |
48 | OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); |
49 | } |
50 | CXX_OPERATOR_ATTRIBUTE |
51 | void *operator new[](size_t size) { |
52 | OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); |
53 | } |
54 | CXX_OPERATOR_ATTRIBUTE |
55 | void *operator new(size_t size, std::nothrow_t const &) { |
56 | OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); |
57 | } |
58 | CXX_OPERATOR_ATTRIBUTE |
59 | void *operator new[](size_t size, std::nothrow_t const &) { |
60 | OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); |
61 | } |
62 | CXX_OPERATOR_ATTRIBUTE |
63 | void *operator new(size_t size, std::align_val_t align) { |
64 | OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); |
65 | } |
66 | CXX_OPERATOR_ATTRIBUTE |
67 | void *operator new[](size_t size, std::align_val_t align) { |
68 | OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); |
69 | } |
70 | CXX_OPERATOR_ATTRIBUTE |
71 | void *operator new(size_t size, std::align_val_t align, |
72 | std::nothrow_t const &) { |
73 | OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); |
74 | } |
75 | CXX_OPERATOR_ATTRIBUTE |
76 | void *operator new[](size_t size, std::align_val_t align, |
77 | std::nothrow_t const &) { |
78 | OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); |
79 | } |
80 | |
81 | #define OPERATOR_DELETE_BODY(type) \ |
82 | GET_STACK_TRACE_FREE; \ |
83 | memprof_delete(ptr, 0, 0, &stack, type); |
84 | |
85 | #define OPERATOR_DELETE_BODY_SIZE(type) \ |
86 | GET_STACK_TRACE_FREE; \ |
87 | memprof_delete(ptr, size, 0, &stack, type); |
88 | |
89 | #define OPERATOR_DELETE_BODY_ALIGN(type) \ |
90 | GET_STACK_TRACE_FREE; \ |
91 | memprof_delete(ptr, 0, static_cast<uptr>(align), &stack, type); |
92 | |
93 | #define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ |
94 | GET_STACK_TRACE_FREE; \ |
95 | memprof_delete(ptr, size, static_cast<uptr>(align), &stack, type); |
96 | |
97 | CXX_OPERATOR_ATTRIBUTE |
98 | void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); } |
99 | CXX_OPERATOR_ATTRIBUTE |
100 | void operator delete[](void *ptr) NOEXCEPT { |
101 | OPERATOR_DELETE_BODY(FROM_NEW_BR); |
102 | } |
103 | CXX_OPERATOR_ATTRIBUTE |
104 | void operator delete(void *ptr, std::nothrow_t const &) { |
105 | OPERATOR_DELETE_BODY(FROM_NEW); |
106 | } |
107 | CXX_OPERATOR_ATTRIBUTE |
108 | void operator delete[](void *ptr, std::nothrow_t const &) { |
109 | OPERATOR_DELETE_BODY(FROM_NEW_BR); |
110 | } |
111 | CXX_OPERATOR_ATTRIBUTE |
112 | void operator delete(void *ptr, size_t size)NOEXCEPT { |
113 | OPERATOR_DELETE_BODY_SIZE(FROM_NEW); |
114 | } |
115 | CXX_OPERATOR_ATTRIBUTE |
116 | void operator delete[](void *ptr, size_t size) NOEXCEPT { |
117 | OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); |
118 | } |
119 | CXX_OPERATOR_ATTRIBUTE |
120 | void operator delete(void *ptr, std::align_val_t align)NOEXCEPT { |
121 | OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); |
122 | } |
123 | CXX_OPERATOR_ATTRIBUTE |
124 | void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT { |
125 | OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); |
126 | } |
127 | CXX_OPERATOR_ATTRIBUTE |
128 | void operator delete(void *ptr, std::align_val_t align, |
129 | std::nothrow_t const &) { |
130 | OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); |
131 | } |
132 | CXX_OPERATOR_ATTRIBUTE |
133 | void operator delete[](void *ptr, std::align_val_t align, |
134 | std::nothrow_t const &) { |
135 | OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); |
136 | } |
137 | CXX_OPERATOR_ATTRIBUTE |
138 | void operator delete(void *ptr, size_t size, std::align_val_t align)NOEXCEPT { |
139 | OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); |
140 | } |
141 | CXX_OPERATOR_ATTRIBUTE |
142 | void operator delete[](void *ptr, size_t size, |
143 | std::align_val_t align) NOEXCEPT { |
144 | OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); |
145 | } |
146 | |