1//===-- nsan_new_delete.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 MemorySanitizer.
10//
11// Interceptors for operators new and delete.
12//===----------------------------------------------------------------------===//
13
14#include "interception/interception.h"
15#include "nsan.h"
16#include "nsan_allocator.h"
17#include "sanitizer_common/sanitizer_allocator.h"
18#include "sanitizer_common/sanitizer_allocator_checks.h"
19#include "sanitizer_common/sanitizer_allocator_report.h"
20
21#include <stddef.h>
22
23using namespace __nsan;
24
25// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
26namespace std {
27struct nothrow_t {};
28enum class align_val_t : size_t {};
29} // namespace std
30
31#define OPERATOR_NEW_BODY(nothrow) \
32 void *res = nsan_malloc(size); \
33 if (!nothrow && UNLIKELY(!res)) { \
34 BufferedStackTrace stack; \
35 GET_FATAL_STACK_TRACE_IF_EMPTY(&stack); \
36 ReportOutOfMemory(size, &stack); \
37 } \
38 return res
39#define OPERATOR_NEW_BODY_ALIGN(nothrow) \
40 if (UNLIKELY(!CheckAlignedNewAlignment((uptr)align))) { \
41 BufferedStackTrace stack; \
42 GET_FATAL_STACK_TRACE_IF_EMPTY(&stack); \
43 ReportInvalidAllocationAlignment((uptr)align, &stack); \
44 } \
45 void *res = nsan_memalign((uptr)align, size); \
46 if (!nothrow && UNLIKELY(!res)) { \
47 BufferedStackTrace stack; \
48 GET_FATAL_STACK_TRACE_IF_EMPTY(&stack); \
49 ReportOutOfMemory(size, &stack); \
50 } \
51 return res;
52
53INTERCEPTOR_ATTRIBUTE
54void *operator new(size_t size) { OPERATOR_NEW_BODY(/*nothrow=*/false); }
55INTERCEPTOR_ATTRIBUTE
56void *operator new[](size_t size) { OPERATOR_NEW_BODY(/*nothrow=*/false); }
57INTERCEPTOR_ATTRIBUTE
58void *operator new(size_t size, std::nothrow_t const &) {
59 OPERATOR_NEW_BODY(/*nothrow=*/true);
60}
61INTERCEPTOR_ATTRIBUTE
62void *operator new[](size_t size, std::nothrow_t const &) {
63 OPERATOR_NEW_BODY(/*nothrow=*/true);
64}
65INTERCEPTOR_ATTRIBUTE
66void *operator new(size_t size, std::align_val_t align) {
67 OPERATOR_NEW_BODY_ALIGN(/*nothrow=*/false);
68}
69INTERCEPTOR_ATTRIBUTE
70void *operator new[](size_t size, std::align_val_t align) {
71 OPERATOR_NEW_BODY_ALIGN(/*nothrow=*/false);
72}
73INTERCEPTOR_ATTRIBUTE
74void *operator new(size_t size, std::align_val_t align,
75 std::nothrow_t const &) {
76 OPERATOR_NEW_BODY_ALIGN(/*nothrow=*/true);
77}
78INTERCEPTOR_ATTRIBUTE
79void *operator new[](size_t size, std::align_val_t align,
80 std::nothrow_t const &) {
81 OPERATOR_NEW_BODY_ALIGN(/*nothrow=*/true);
82}
83
84#define OPERATOR_DELETE_BODY \
85 if (ptr) \
86 NsanDeallocate(ptr)
87
88INTERCEPTOR_ATTRIBUTE
89void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
90INTERCEPTOR_ATTRIBUTE
91void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
92INTERCEPTOR_ATTRIBUTE
93void operator delete(void *ptr, std::nothrow_t const &) {
94 OPERATOR_DELETE_BODY;
95}
96INTERCEPTOR_ATTRIBUTE
97void operator delete[](void *ptr, std::nothrow_t const &) {
98 OPERATOR_DELETE_BODY;
99}
100INTERCEPTOR_ATTRIBUTE
101void operator delete(void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; }
102INTERCEPTOR_ATTRIBUTE
103void operator delete[](void *ptr, size_t size) NOEXCEPT {
104 OPERATOR_DELETE_BODY;
105}
106INTERCEPTOR_ATTRIBUTE
107void operator delete(void *ptr, std::align_val_t align) NOEXCEPT {
108 OPERATOR_DELETE_BODY;
109}
110INTERCEPTOR_ATTRIBUTE
111void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {
112 OPERATOR_DELETE_BODY;
113}
114INTERCEPTOR_ATTRIBUTE
115void operator delete(void *ptr, std::align_val_t align,
116 std::nothrow_t const &) {
117 OPERATOR_DELETE_BODY;
118}
119INTERCEPTOR_ATTRIBUTE
120void operator delete[](void *ptr, std::align_val_t align,
121 std::nothrow_t const &) {
122 OPERATOR_DELETE_BODY;
123}
124INTERCEPTOR_ATTRIBUTE
125void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT {
126 OPERATOR_DELETE_BODY;
127}
128INTERCEPTOR_ATTRIBUTE
129void operator delete[](void *ptr, size_t size,
130 std::align_val_t align) NOEXCEPT {
131 OPERATOR_DELETE_BODY;
132}
133