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_checks.h"
18#include "sanitizer_common/sanitizer_allocator_report.h"
19
20#include "interception/interception.h"
21
22#include <stddef.h>
23
24#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
25
26using namespace __memprof;
27
28// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
29namespace std {
30struct nothrow_t {};
31enum class align_val_t : size_t {};
32} // namespace std
33
34#define OPERATOR_NEW_BODY(type, nothrow) \
35 GET_STACK_TRACE_MALLOC; \
36 void *res = memprof_memalign(0, size, &stack, type); \
37 if (!nothrow && UNLIKELY(!res)) \
38 ReportOutOfMemory(size, &stack); \
39 return res;
40#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
41 GET_STACK_TRACE_MALLOC; \
42 if (UNLIKELY(!CheckAlignedNewAlignment((uptr)align))) \
43 ReportInvalidAllocationAlignment((uptr)align, &stack); \
44 void *res = memprof_memalign((uptr)align, size, &stack, type); \
45 if (!nothrow && UNLIKELY(!res)) \
46 ReportOutOfMemory(size, &stack); \
47 return res;
48
49CXX_OPERATOR_ATTRIBUTE
50void *operator new(size_t size) {
51 OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
52}
53CXX_OPERATOR_ATTRIBUTE
54void *operator new[](size_t size) {
55 OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
56}
57CXX_OPERATOR_ATTRIBUTE
58void *operator new(size_t size, std::nothrow_t const &) {
59 OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
60}
61CXX_OPERATOR_ATTRIBUTE
62void *operator new[](size_t size, std::nothrow_t const &) {
63 OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
64}
65CXX_OPERATOR_ATTRIBUTE
66void *operator new(size_t size, std::align_val_t align) {
67 OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/);
68}
69CXX_OPERATOR_ATTRIBUTE
70void *operator new[](size_t size, std::align_val_t align) {
71 OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/);
72}
73CXX_OPERATOR_ATTRIBUTE
74void *operator new(size_t size, std::align_val_t align,
75 std::nothrow_t const &) {
76 OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/);
77}
78CXX_OPERATOR_ATTRIBUTE
79void *operator new[](size_t size, std::align_val_t align,
80 std::nothrow_t const &) {
81 OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/);
82}
83
84#define OPERATOR_DELETE_BODY(type) \
85 GET_STACK_TRACE_FREE; \
86 memprof_delete(ptr, 0, 0, &stack, type);
87
88#define OPERATOR_DELETE_BODY_SIZE(type) \
89 GET_STACK_TRACE_FREE; \
90 memprof_delete(ptr, size, 0, &stack, type);
91
92#define OPERATOR_DELETE_BODY_ALIGN(type) \
93 GET_STACK_TRACE_FREE; \
94 memprof_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
95
96#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
97 GET_STACK_TRACE_FREE; \
98 memprof_delete(ptr, size, static_cast<uptr>(align), &stack, type);
99
100CXX_OPERATOR_ATTRIBUTE
101void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); }
102CXX_OPERATOR_ATTRIBUTE
103void operator delete[](void *ptr) NOEXCEPT {
104 OPERATOR_DELETE_BODY(FROM_NEW_BR);
105}
106CXX_OPERATOR_ATTRIBUTE
107void operator delete(void *ptr, std::nothrow_t const &) {
108 OPERATOR_DELETE_BODY(FROM_NEW);
109}
110CXX_OPERATOR_ATTRIBUTE
111void operator delete[](void *ptr, std::nothrow_t const &) {
112 OPERATOR_DELETE_BODY(FROM_NEW_BR);
113}
114CXX_OPERATOR_ATTRIBUTE
115void operator delete(void *ptr, size_t size)NOEXCEPT {
116 OPERATOR_DELETE_BODY_SIZE(FROM_NEW);
117}
118CXX_OPERATOR_ATTRIBUTE
119void operator delete[](void *ptr, size_t size) NOEXCEPT {
120 OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR);
121}
122CXX_OPERATOR_ATTRIBUTE
123void operator delete(void *ptr, std::align_val_t align)NOEXCEPT {
124 OPERATOR_DELETE_BODY_ALIGN(FROM_NEW);
125}
126CXX_OPERATOR_ATTRIBUTE
127void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {
128 OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR);
129}
130CXX_OPERATOR_ATTRIBUTE
131void operator delete(void *ptr, std::align_val_t align,
132 std::nothrow_t const &) {
133 OPERATOR_DELETE_BODY_ALIGN(FROM_NEW);
134}
135CXX_OPERATOR_ATTRIBUTE
136void operator delete[](void *ptr, std::align_val_t align,
137 std::nothrow_t const &) {
138 OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR);
139}
140CXX_OPERATOR_ATTRIBUTE
141void operator delete(void *ptr, size_t size, std::align_val_t align)NOEXCEPT {
142 OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW);
143}
144CXX_OPERATOR_ATTRIBUTE
145void operator delete[](void *ptr, size_t size,
146 std::align_val_t align) NOEXCEPT {
147 OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR);
148}
149