1353944Sdim//===-- asan_interceptors.cpp ---------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker. 10353944Sdim// 11353944Sdim// Interceptors for operators new and delete. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "asan_allocator.h" 15353944Sdim#include "asan_internal.h" 16353944Sdim#include "asan_malloc_local.h" 17353944Sdim#include "asan_report.h" 18353944Sdim#include "asan_stack.h" 19353944Sdim 20353944Sdim#include "interception/interception.h" 21353944Sdim 22353944Sdim#include <stddef.h> 23353944Sdim 24353944Sdim// C++ operators can't have dllexport attributes on Windows. We export them 25353944Sdim// anyway by passing extra -export flags to the linker, which is exactly that 26353944Sdim// dllexport would normally do. We need to export them in order to make the 27353944Sdim// VS2015 dynamic CRT (MD) work. 28353944Sdim#if SANITIZER_WINDOWS && defined(_MSC_VER) 29353944Sdim#define CXX_OPERATOR_ATTRIBUTE 30353944Sdim#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym)) 31353944Sdim#ifdef _WIN64 32353944SdimCOMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new 33353944SdimCOMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow 34353944SdimCOMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete 35353944SdimCOMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete 36353944SdimCOMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[] 37353944SdimCOMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[] 38353944Sdim#else 39353944SdimCOMMENT_EXPORT("??2@YAPAXI@Z") // operator new 40353944SdimCOMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow 41353944SdimCOMMENT_EXPORT("??3@YAXPAX@Z") // operator delete 42353944SdimCOMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete 43353944SdimCOMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[] 44353944SdimCOMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] 45353944Sdim#endif 46353944Sdim#undef COMMENT_EXPORT 47353944Sdim#else 48353944Sdim#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE 49353944Sdim#endif 50353944Sdim 51353944Sdimusing namespace __asan; 52353944Sdim 53353944Sdim// FreeBSD prior v9.2 have wrong definition of 'size_t'. 54353944Sdim// http://svnweb.freebsd.org/base?view=revision&revision=232261 55353944Sdim#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 56353944Sdim#include <sys/param.h> 57353944Sdim#if __FreeBSD_version <= 902001 // v9.2 58353944Sdim#define size_t unsigned 59353944Sdim#endif // __FreeBSD_version 60353944Sdim#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 61353944Sdim 62353944Sdim// This code has issues on OSX. 63353944Sdim// See https://github.com/google/sanitizers/issues/131. 64353944Sdim 65353944Sdim// Fake std::nothrow_t and std::align_val_t to avoid including <new>. 66353944Sdimnamespace std { 67353944Sdimstruct nothrow_t {}; 68353944Sdimenum class align_val_t: size_t {}; 69353944Sdim} // namespace std 70353944Sdim 71353944Sdim// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. 72353944Sdim// For local pool allocation, align to SHADOW_GRANULARITY to match asan 73353944Sdim// allocator behavior. 74353944Sdim#define OPERATOR_NEW_BODY(type, nothrow) \ 75353944Sdim MAYBE_ALLOCATE_FROM_LOCAL_POOL(nothrow); \ 76353944Sdim GET_STACK_TRACE_MALLOC; \ 77353944Sdim void *res = asan_memalign(0, size, &stack, type); \ 78353944Sdim if (!nothrow && UNLIKELY(!res)) \ 79353944Sdim ReportOutOfMemory(size, &stack); \ 80353944Sdim return res; 81353944Sdim#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ 82353944Sdim MAYBE_ALLOCATE_FROM_LOCAL_POOL(nothrow); \ 83353944Sdim GET_STACK_TRACE_MALLOC; \ 84353944Sdim void *res = asan_memalign((uptr)align, size, &stack, type); \ 85353944Sdim if (!nothrow && UNLIKELY(!res)) \ 86353944Sdim ReportOutOfMemory(size, &stack); \ 87353944Sdim return res; 88353944Sdim 89353944Sdim// On OS X it's not enough to just provide our own 'operator new' and 90353944Sdim// 'operator delete' implementations, because they're going to be in the 91353944Sdim// runtime dylib, and the main executable will depend on both the runtime 92353944Sdim// dylib and libstdc++, each of those'll have its implementation of new and 93353944Sdim// delete. 94353944Sdim// To make sure that C++ allocation/deallocation operators are overridden on 95353944Sdim// OS X we need to intercept them using their mangled names. 96353944Sdim#if !SANITIZER_MAC 97353944SdimCXX_OPERATOR_ATTRIBUTE 98353944Sdimvoid *operator new(size_t size) 99353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); } 100353944SdimCXX_OPERATOR_ATTRIBUTE 101353944Sdimvoid *operator new[](size_t size) 102353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); } 103353944SdimCXX_OPERATOR_ATTRIBUTE 104353944Sdimvoid *operator new(size_t size, std::nothrow_t const&) 105353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); } 106353944SdimCXX_OPERATOR_ATTRIBUTE 107353944Sdimvoid *operator new[](size_t size, std::nothrow_t const&) 108353944Sdim{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); } 109353944SdimCXX_OPERATOR_ATTRIBUTE 110353944Sdimvoid *operator new(size_t size, std::align_val_t align) 111353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); } 112353944SdimCXX_OPERATOR_ATTRIBUTE 113353944Sdimvoid *operator new[](size_t size, std::align_val_t align) 114353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); } 115353944SdimCXX_OPERATOR_ATTRIBUTE 116353944Sdimvoid *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) 117353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); } 118353944SdimCXX_OPERATOR_ATTRIBUTE 119353944Sdimvoid *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) 120353944Sdim{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); } 121353944Sdim 122353944Sdim#else // SANITIZER_MAC 123353944SdimINTERCEPTOR(void *, _Znwm, size_t size) { 124353944Sdim OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); 125353944Sdim} 126353944SdimINTERCEPTOR(void *, _Znam, size_t size) { 127353944Sdim OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); 128353944Sdim} 129353944SdimINTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { 130353944Sdim OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); 131353944Sdim} 132353944SdimINTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { 133353944Sdim OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); 134353944Sdim} 135353944Sdim#endif // !SANITIZER_MAC 136353944Sdim 137353944Sdim#define OPERATOR_DELETE_BODY(type) \ 138353944Sdim if (IS_FROM_LOCAL_POOL(ptr)) return;\ 139353944Sdim GET_STACK_TRACE_FREE;\ 140353944Sdim asan_delete(ptr, 0, 0, &stack, type); 141353944Sdim 142353944Sdim#define OPERATOR_DELETE_BODY_SIZE(type) \ 143353944Sdim if (IS_FROM_LOCAL_POOL(ptr)) return;\ 144353944Sdim GET_STACK_TRACE_FREE;\ 145353944Sdim asan_delete(ptr, size, 0, &stack, type); 146353944Sdim 147353944Sdim#define OPERATOR_DELETE_BODY_ALIGN(type) \ 148353944Sdim if (IS_FROM_LOCAL_POOL(ptr)) return;\ 149353944Sdim GET_STACK_TRACE_FREE;\ 150353944Sdim asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type); 151353944Sdim 152353944Sdim#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ 153353944Sdim if (IS_FROM_LOCAL_POOL(ptr)) return;\ 154353944Sdim GET_STACK_TRACE_FREE;\ 155353944Sdim asan_delete(ptr, size, static_cast<uptr>(align), &stack, type); 156353944Sdim 157353944Sdim#if !SANITIZER_MAC 158353944SdimCXX_OPERATOR_ATTRIBUTE 159353944Sdimvoid operator delete(void *ptr) NOEXCEPT 160353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); } 161353944SdimCXX_OPERATOR_ATTRIBUTE 162353944Sdimvoid operator delete[](void *ptr) NOEXCEPT 163353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } 164353944SdimCXX_OPERATOR_ATTRIBUTE 165353944Sdimvoid operator delete(void *ptr, std::nothrow_t const&) 166353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); } 167353944SdimCXX_OPERATOR_ATTRIBUTE 168353944Sdimvoid operator delete[](void *ptr, std::nothrow_t const&) 169353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } 170353944SdimCXX_OPERATOR_ATTRIBUTE 171353944Sdimvoid operator delete(void *ptr, size_t size) NOEXCEPT 172353944Sdim{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); } 173353944SdimCXX_OPERATOR_ATTRIBUTE 174353944Sdimvoid operator delete[](void *ptr, size_t size) NOEXCEPT 175353944Sdim{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); } 176353944SdimCXX_OPERATOR_ATTRIBUTE 177353944Sdimvoid operator delete(void *ptr, std::align_val_t align) NOEXCEPT 178353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } 179353944SdimCXX_OPERATOR_ATTRIBUTE 180353944Sdimvoid operator delete[](void *ptr, std::align_val_t align) NOEXCEPT 181353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } 182353944SdimCXX_OPERATOR_ATTRIBUTE 183353944Sdimvoid operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) 184353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } 185353944SdimCXX_OPERATOR_ATTRIBUTE 186353944Sdimvoid operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) 187353944Sdim{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } 188353944SdimCXX_OPERATOR_ATTRIBUTE 189353944Sdimvoid operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT 190353944Sdim{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); } 191353944SdimCXX_OPERATOR_ATTRIBUTE 192353944Sdimvoid operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT 193353944Sdim{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); } 194353944Sdim 195353944Sdim#else // SANITIZER_MAC 196353944SdimINTERCEPTOR(void, _ZdlPv, void *ptr) 197353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); } 198353944SdimINTERCEPTOR(void, _ZdaPv, void *ptr) 199353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } 200353944SdimINTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 201353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW); } 202353944SdimINTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 203353944Sdim{ OPERATOR_DELETE_BODY(FROM_NEW_BR); } 204353944Sdim#endif // !SANITIZER_MAC 205