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
25using namespace __memprof;
26
27// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
28namespace std {
29struct nothrow_t {};
30enum 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
46CXX_OPERATOR_ATTRIBUTE
47void *operator new(size_t size) {
48  OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
49}
50CXX_OPERATOR_ATTRIBUTE
51void *operator new[](size_t size) {
52  OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
53}
54CXX_OPERATOR_ATTRIBUTE
55void *operator new(size_t size, std::nothrow_t const &) {
56  OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
57}
58CXX_OPERATOR_ATTRIBUTE
59void *operator new[](size_t size, std::nothrow_t const &) {
60  OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
61}
62CXX_OPERATOR_ATTRIBUTE
63void *operator new(size_t size, std::align_val_t align) {
64  OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/);
65}
66CXX_OPERATOR_ATTRIBUTE
67void *operator new[](size_t size, std::align_val_t align) {
68  OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/);
69}
70CXX_OPERATOR_ATTRIBUTE
71void *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}
75CXX_OPERATOR_ATTRIBUTE
76void *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
97CXX_OPERATOR_ATTRIBUTE
98void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY(FROM_NEW); }
99CXX_OPERATOR_ATTRIBUTE
100void operator delete[](void *ptr) NOEXCEPT {
101  OPERATOR_DELETE_BODY(FROM_NEW_BR);
102}
103CXX_OPERATOR_ATTRIBUTE
104void operator delete(void *ptr, std::nothrow_t const &) {
105  OPERATOR_DELETE_BODY(FROM_NEW);
106}
107CXX_OPERATOR_ATTRIBUTE
108void operator delete[](void *ptr, std::nothrow_t const &) {
109  OPERATOR_DELETE_BODY(FROM_NEW_BR);
110}
111CXX_OPERATOR_ATTRIBUTE
112void operator delete(void *ptr, size_t size)NOEXCEPT {
113  OPERATOR_DELETE_BODY_SIZE(FROM_NEW);
114}
115CXX_OPERATOR_ATTRIBUTE
116void operator delete[](void *ptr, size_t size) NOEXCEPT {
117  OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR);
118}
119CXX_OPERATOR_ATTRIBUTE
120void operator delete(void *ptr, std::align_val_t align)NOEXCEPT {
121  OPERATOR_DELETE_BODY_ALIGN(FROM_NEW);
122}
123CXX_OPERATOR_ATTRIBUTE
124void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {
125  OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR);
126}
127CXX_OPERATOR_ATTRIBUTE
128void operator delete(void *ptr, std::align_val_t align,
129                     std::nothrow_t const &) {
130  OPERATOR_DELETE_BODY_ALIGN(FROM_NEW);
131}
132CXX_OPERATOR_ATTRIBUTE
133void operator delete[](void *ptr, std::align_val_t align,
134                       std::nothrow_t const &) {
135  OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR);
136}
137CXX_OPERATOR_ATTRIBUTE
138void operator delete(void *ptr, size_t size, std::align_val_t align)NOEXCEPT {
139  OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW);
140}
141CXX_OPERATOR_ATTRIBUTE
142void 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