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