1*fe6060f1SDimitry Andric //===-- dfsan_new_delete.cpp ----------------------------------------------===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric //
9*fe6060f1SDimitry Andric // This file is a part of DataflowSanitizer.
10*fe6060f1SDimitry Andric //
11*fe6060f1SDimitry Andric // Interceptors for operators new and delete.
12*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
13*fe6060f1SDimitry Andric
14*fe6060f1SDimitry Andric #include <stddef.h>
15*fe6060f1SDimitry Andric
16*fe6060f1SDimitry Andric #include "dfsan.h"
17*fe6060f1SDimitry Andric #include "interception/interception.h"
18*fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_allocator.h"
19*fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h"
20*fe6060f1SDimitry Andric
21*fe6060f1SDimitry Andric using namespace __dfsan;
22*fe6060f1SDimitry Andric
23*fe6060f1SDimitry Andric // Fake std::nothrow_t and std::align_val_t to avoid including <new>.
24*fe6060f1SDimitry Andric namespace std {
25*fe6060f1SDimitry Andric struct nothrow_t {};
26*fe6060f1SDimitry Andric enum class align_val_t : size_t {};
27*fe6060f1SDimitry Andric } // namespace std
28*fe6060f1SDimitry Andric
29*fe6060f1SDimitry Andric // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
30*fe6060f1SDimitry Andric #define OPERATOR_NEW_BODY(nothrow) \
31*fe6060f1SDimitry Andric void *res = dfsan_malloc(size); \
32*fe6060f1SDimitry Andric if (!nothrow && UNLIKELY(!res)) { \
33*fe6060f1SDimitry Andric BufferedStackTrace stack; \
34*fe6060f1SDimitry Andric ReportOutOfMemory(size, &stack); \
35*fe6060f1SDimitry Andric } \
36*fe6060f1SDimitry Andric return res
37*fe6060f1SDimitry Andric #define OPERATOR_NEW_BODY_ALIGN(nothrow) \
38*fe6060f1SDimitry Andric void *res = dfsan_memalign((uptr)align, size); \
39*fe6060f1SDimitry Andric if (!nothrow && UNLIKELY(!res)) { \
40*fe6060f1SDimitry Andric BufferedStackTrace stack; \
41*fe6060f1SDimitry Andric ReportOutOfMemory(size, &stack); \
42*fe6060f1SDimitry Andric } \
43*fe6060f1SDimitry Andric return res;
44*fe6060f1SDimitry Andric
45*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new(size_t size)46*fe6060f1SDimitry Andric void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
47*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new[](size_t size)48*fe6060f1SDimitry Andric void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
49*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new(size_t size,std::nothrow_t const &)50*fe6060f1SDimitry Andric void *operator new(size_t size, std::nothrow_t const &) {
51*fe6060f1SDimitry Andric OPERATOR_NEW_BODY(true /*nothrow*/);
52*fe6060f1SDimitry Andric }
53*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new[](size_t size,std::nothrow_t const &)54*fe6060f1SDimitry Andric void *operator new[](size_t size, std::nothrow_t const &) {
55*fe6060f1SDimitry Andric OPERATOR_NEW_BODY(true /*nothrow*/);
56*fe6060f1SDimitry Andric }
57*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new(size_t size,std::align_val_t align)58*fe6060f1SDimitry Andric void *operator new(size_t size, std::align_val_t align) {
59*fe6060f1SDimitry Andric OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/);
60*fe6060f1SDimitry Andric }
61*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new[](size_t size,std::align_val_t align)62*fe6060f1SDimitry Andric void *operator new[](size_t size, std::align_val_t align) {
63*fe6060f1SDimitry Andric OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/);
64*fe6060f1SDimitry Andric }
65*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new(size_t size,std::align_val_t align,std::nothrow_t const &)66*fe6060f1SDimitry Andric void *operator new(size_t size, std::align_val_t align,
67*fe6060f1SDimitry Andric std::nothrow_t const &) {
68*fe6060f1SDimitry Andric OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/);
69*fe6060f1SDimitry Andric }
70*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator new[](size_t size,std::align_val_t align,std::nothrow_t const &)71*fe6060f1SDimitry Andric void *operator new[](size_t size, std::align_val_t align,
72*fe6060f1SDimitry Andric std::nothrow_t const &) {
73*fe6060f1SDimitry Andric OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/);
74*fe6060f1SDimitry Andric }
75*fe6060f1SDimitry Andric
76*fe6060f1SDimitry Andric #define OPERATOR_DELETE_BODY \
77*fe6060f1SDimitry Andric if (ptr) \
78*fe6060f1SDimitry Andric dfsan_deallocate(ptr)
79*fe6060f1SDimitry Andric
80*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr)81*fe6060f1SDimitry Andric void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY; }
82*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr)83*fe6060f1SDimitry Andric void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
84*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr,std::nothrow_t const &)85*fe6060f1SDimitry Andric void operator delete(void *ptr, std::nothrow_t const &) {
86*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
87*fe6060f1SDimitry Andric }
88*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr,std::nothrow_t const &)89*fe6060f1SDimitry Andric void operator delete[](void *ptr, std::nothrow_t const &) {
90*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
91*fe6060f1SDimitry Andric }
92*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr,size_t size)93*fe6060f1SDimitry Andric void operator delete(void *ptr, size_t size)NOEXCEPT { OPERATOR_DELETE_BODY; }
94*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr,size_t size)95*fe6060f1SDimitry Andric void operator delete[](void *ptr, size_t size) NOEXCEPT {
96*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
97*fe6060f1SDimitry Andric }
98*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr,std::align_val_t align)99*fe6060f1SDimitry Andric void operator delete(void *ptr, std::align_val_t align)NOEXCEPT {
100*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
101*fe6060f1SDimitry Andric }
102*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr,std::align_val_t align)103*fe6060f1SDimitry Andric void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {
104*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
105*fe6060f1SDimitry Andric }
106*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr,std::align_val_t align,std::nothrow_t const &)107*fe6060f1SDimitry Andric void operator delete(void *ptr, std::align_val_t align,
108*fe6060f1SDimitry Andric std::nothrow_t const &) {
109*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
110*fe6060f1SDimitry Andric }
111*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr,std::align_val_t align,std::nothrow_t const &)112*fe6060f1SDimitry Andric void operator delete[](void *ptr, std::align_val_t align,
113*fe6060f1SDimitry Andric std::nothrow_t const &) {
114*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
115*fe6060f1SDimitry Andric }
116*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete(void * ptr,size_t size,std::align_val_t align)117*fe6060f1SDimitry Andric void operator delete(void *ptr, size_t size, std::align_val_t align)NOEXCEPT {
118*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
119*fe6060f1SDimitry Andric }
120*fe6060f1SDimitry Andric INTERCEPTOR_ATTRIBUTE
operator delete[](void * ptr,size_t size,std::align_val_t align)121*fe6060f1SDimitry Andric void operator delete[](void *ptr, size_t size,
122*fe6060f1SDimitry Andric std::align_val_t align) NOEXCEPT {
123*fe6060f1SDimitry Andric OPERATOR_DELETE_BODY;
124*fe6060f1SDimitry Andric }
125