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