168d75effSDimitry Andric //===-- asan_interceptors.cpp ---------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Interceptors for operators new and delete. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 14fe6060f1SDimitry Andric #include <stddef.h> 15fe6060f1SDimitry Andric 1668d75effSDimitry Andric #include "asan_allocator.h" 1768d75effSDimitry Andric #include "asan_internal.h" 1868d75effSDimitry Andric #include "asan_report.h" 1968d75effSDimitry Andric #include "asan_stack.h" 2068d75effSDimitry Andric #include "interception/interception.h" 2168d75effSDimitry Andric 2268d75effSDimitry Andric // C++ operators can't have dllexport attributes on Windows. We export them 2368d75effSDimitry Andric // anyway by passing extra -export flags to the linker, which is exactly that 2468d75effSDimitry Andric // dllexport would normally do. We need to export them in order to make the 2568d75effSDimitry Andric // VS2015 dynamic CRT (MD) work. 2668d75effSDimitry Andric #if SANITIZER_WINDOWS && defined(_MSC_VER) 2768d75effSDimitry Andric #define CXX_OPERATOR_ATTRIBUTE 2868d75effSDimitry Andric #define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym)) 2968d75effSDimitry Andric #ifdef _WIN64 3068d75effSDimitry Andric COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new 3168d75effSDimitry Andric COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow 3268d75effSDimitry Andric COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete 3368d75effSDimitry Andric COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete 3468d75effSDimitry Andric COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[] 3568d75effSDimitry Andric COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[] 3668d75effSDimitry Andric #else 3768d75effSDimitry Andric COMMENT_EXPORT("??2@YAPAXI@Z") // operator new 3868d75effSDimitry Andric COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow 3968d75effSDimitry Andric COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete 4068d75effSDimitry Andric COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete 4168d75effSDimitry Andric COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[] 4268d75effSDimitry Andric COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] 4368d75effSDimitry Andric #endif 4468d75effSDimitry Andric #undef COMMENT_EXPORT 4568d75effSDimitry Andric #else 46fe6060f1SDimitry Andric #define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 4768d75effSDimitry Andric #endif 4868d75effSDimitry Andric 4968d75effSDimitry Andric using namespace __asan; 5068d75effSDimitry Andric 5168d75effSDimitry Andric // This code has issues on OSX. 5268d75effSDimitry Andric // See https://github.com/google/sanitizers/issues/131. 5368d75effSDimitry Andric 5468d75effSDimitry Andric // Fake std::nothrow_t and std::align_val_t to avoid including <new>. 5568d75effSDimitry Andric namespace std { 5668d75effSDimitry Andric struct nothrow_t {}; 5768d75effSDimitry Andric enum class align_val_t: size_t {}; 5868d75effSDimitry Andric } // namespace std 5968d75effSDimitry Andric 6068d75effSDimitry Andric // TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. 6168d75effSDimitry Andric // For local pool allocation, align to SHADOW_GRANULARITY to match asan 6268d75effSDimitry Andric // allocator behavior. 6368d75effSDimitry Andric #define OPERATOR_NEW_BODY(type, nothrow) \ 6468d75effSDimitry Andric GET_STACK_TRACE_MALLOC; \ 6568d75effSDimitry Andric void *res = asan_memalign(0, size, &stack, type); \ 6668d75effSDimitry Andric if (!nothrow && UNLIKELY(!res)) \ 6768d75effSDimitry Andric ReportOutOfMemory(size, &stack); \ 6868d75effSDimitry Andric return res; 6968d75effSDimitry Andric #define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ 7068d75effSDimitry Andric GET_STACK_TRACE_MALLOC; \ 7168d75effSDimitry Andric void *res = asan_memalign((uptr)align, size, &stack, type); \ 7268d75effSDimitry Andric if (!nothrow && UNLIKELY(!res)) \ 7368d75effSDimitry Andric ReportOutOfMemory(size, &stack); \ 7468d75effSDimitry Andric return res; 7568d75effSDimitry Andric 7668d75effSDimitry Andric // On OS X it's not enough to just provide our own 'operator new' and 7768d75effSDimitry Andric // 'operator delete' implementations, because they're going to be in the 7868d75effSDimitry Andric // runtime dylib, and the main executable will depend on both the runtime 7968d75effSDimitry Andric // dylib and libstdc++, each of those'll have its implementation of new and 8068d75effSDimitry Andric // delete. 8168d75effSDimitry Andric // To make sure that C++ allocation/deallocation operators are overridden on 8268d75effSDimitry Andric // OS X we need to intercept them using their mangled names. 83*81ad6265SDimitry Andric #if !SANITIZER_APPLE 8468d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 8568d75effSDimitry Andric void *operator new(size_t size) 8668d75effSDimitry Andric { OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); } 8768d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 8868d75effSDimitry Andric void *operator new[](size_t size) 8968d75effSDimitry Andric { OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); } 9068d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 9168d75effSDimitry Andric void *operator new(size_t size, std::nothrow_t const&) 9268d75effSDimitry Andric { OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); } 9368d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 9468d75effSDimitry Andric void *operator new[](size_t size, std::nothrow_t const&) 9568d75effSDimitry Andric { OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); } 9668d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 9768d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align) 9868d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); } 9968d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 10068d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align) 10168d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); } 10268d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 10368d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) 10468d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); } 10568d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 10668d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) 10768d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); } 10868d75effSDimitry Andric 109*81ad6265SDimitry Andric #else // SANITIZER_APPLE 11068d75effSDimitry Andric INTERCEPTOR(void *, _Znwm, size_t size) { 11168d75effSDimitry Andric OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); 11268d75effSDimitry Andric } 11368d75effSDimitry Andric INTERCEPTOR(void *, _Znam, size_t size) { 11468d75effSDimitry Andric OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); 11568d75effSDimitry Andric } 11668d75effSDimitry Andric INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) { 11768d75effSDimitry Andric OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); 11868d75effSDimitry Andric } 11968d75effSDimitry Andric INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { 12068d75effSDimitry Andric OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); 12168d75effSDimitry Andric } 122*81ad6265SDimitry Andric #endif // !SANITIZER_APPLE 12368d75effSDimitry Andric 12468d75effSDimitry Andric #define OPERATOR_DELETE_BODY(type) \ 12568d75effSDimitry Andric GET_STACK_TRACE_FREE; \ 12668d75effSDimitry Andric asan_delete(ptr, 0, 0, &stack, type); 12768d75effSDimitry Andric 12868d75effSDimitry Andric #define OPERATOR_DELETE_BODY_SIZE(type) \ 12968d75effSDimitry Andric GET_STACK_TRACE_FREE; \ 13068d75effSDimitry Andric asan_delete(ptr, size, 0, &stack, type); 13168d75effSDimitry Andric 13268d75effSDimitry Andric #define OPERATOR_DELETE_BODY_ALIGN(type) \ 13368d75effSDimitry Andric GET_STACK_TRACE_FREE; \ 13468d75effSDimitry Andric asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type); 13568d75effSDimitry Andric 13668d75effSDimitry Andric #define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ 13768d75effSDimitry Andric GET_STACK_TRACE_FREE; \ 13868d75effSDimitry Andric asan_delete(ptr, size, static_cast<uptr>(align), &stack, type); 13968d75effSDimitry Andric 140*81ad6265SDimitry Andric #if !SANITIZER_APPLE 14168d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 14268d75effSDimitry Andric void operator delete(void *ptr) NOEXCEPT 14368d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW); } 14468d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 14568d75effSDimitry Andric void operator delete[](void *ptr) NOEXCEPT 14668d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW_BR); } 14768d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 14868d75effSDimitry Andric void operator delete(void *ptr, std::nothrow_t const&) 14968d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW); } 15068d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 15168d75effSDimitry Andric void operator delete[](void *ptr, std::nothrow_t const&) 15268d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW_BR); } 15368d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 15468d75effSDimitry Andric void operator delete(void *ptr, size_t size) NOEXCEPT 15568d75effSDimitry Andric { OPERATOR_DELETE_BODY_SIZE(FROM_NEW); } 15668d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 15768d75effSDimitry Andric void operator delete[](void *ptr, size_t size) NOEXCEPT 15868d75effSDimitry Andric { OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); } 15968d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 16068d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t align) NOEXCEPT 16168d75effSDimitry Andric { OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } 16268d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 16368d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT 16468d75effSDimitry Andric { OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } 16568d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 16668d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) 16768d75effSDimitry Andric { OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); } 16868d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 16968d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) 17068d75effSDimitry Andric { OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); } 17168d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 17268d75effSDimitry Andric void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT 17368d75effSDimitry Andric { OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); } 17468d75effSDimitry Andric CXX_OPERATOR_ATTRIBUTE 17568d75effSDimitry Andric void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT 17668d75effSDimitry Andric { OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); } 17768d75effSDimitry Andric 178*81ad6265SDimitry Andric #else // SANITIZER_APPLE 17968d75effSDimitry Andric INTERCEPTOR(void, _ZdlPv, void *ptr) 18068d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW); } 18168d75effSDimitry Andric INTERCEPTOR(void, _ZdaPv, void *ptr) 18268d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW_BR); } 18368d75effSDimitry Andric INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 18468d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW); } 18568d75effSDimitry Andric INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 18668d75effSDimitry Andric { OPERATOR_DELETE_BODY(FROM_NEW_BR); } 187*81ad6265SDimitry Andric #endif // !SANITIZER_APPLE 188