234 lines · cpp
1//===-- asan_interceptors.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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of AddressSanitizer, an address sanity checker.10//11// Interceptors for operators new and delete.12//===----------------------------------------------------------------------===//13 14#include <stddef.h>15 16#include "asan_allocator.h"17#include "asan_internal.h"18#include "asan_report.h"19#include "asan_stack.h"20#include "interception/interception.h"21 22// C++ operators can't have dllexport attributes on Windows. We export them23// anyway by passing extra -export flags to the linker, which is exactly that24// dllexport would normally do. We need to export them in order to make the25// VS2015 dynamic CRT (MD) work.26#if SANITIZER_WINDOWS && defined(_MSC_VER)27#define CXX_OPERATOR_ATTRIBUTE28#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))29#ifdef _WIN6430COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new31COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow32COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete33COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete34COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[]35COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[]36#else37COMMENT_EXPORT("??2@YAPAXI@Z") // operator new38COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow39COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete40COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete41COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[]42COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]43#endif44#undef COMMENT_EXPORT45#else46#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE47#endif48 49using namespace __asan;50 51// This code has issues on OSX.52// See https://github.com/google/sanitizers/issues/131.53 54// Fake std::nothrow_t and std::align_val_t to avoid including <new>.55namespace std {56struct nothrow_t {};57enum class align_val_t: size_t {};58} // namespace std59 60// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM.61// For local pool allocation, align to SHADOW_GRANULARITY to match asan62// allocator behavior.63#define OPERATOR_NEW_BODY \64 GET_STACK_TRACE_MALLOC; \65 void *res = asan_new(size, &stack); \66 if (UNLIKELY(!res)) \67 ReportOutOfMemory(size, &stack); \68 return res69#define OPERATOR_NEW_BODY_NOTHROW \70 GET_STACK_TRACE_MALLOC; \71 return asan_new(size, &stack)72#define OPERATOR_NEW_BODY_ARRAY \73 GET_STACK_TRACE_MALLOC; \74 void *res = asan_new_array(size, &stack); \75 if (UNLIKELY(!res)) \76 ReportOutOfMemory(size, &stack); \77 return res78#define OPERATOR_NEW_BODY_ARRAY_NOTHROW \79 GET_STACK_TRACE_MALLOC; \80 return asan_new_array(size, &stack)81#define OPERATOR_NEW_BODY_ALIGN \82 GET_STACK_TRACE_MALLOC; \83 void *res = asan_new_aligned(size, static_cast<uptr>(align), &stack); \84 if (UNLIKELY(!res)) \85 ReportOutOfMemory(size, &stack); \86 return res87#define OPERATOR_NEW_BODY_ALIGN_NOTHROW \88 GET_STACK_TRACE_MALLOC; \89 return asan_new_aligned(size, static_cast<uptr>(align), &stack)90#define OPERATOR_NEW_BODY_ALIGN_ARRAY \91 GET_STACK_TRACE_MALLOC; \92 void *res = asan_new_array_aligned(size, static_cast<uptr>(align), &stack); \93 if (UNLIKELY(!res)) \94 ReportOutOfMemory(size, &stack); \95 return res96#define OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW \97 GET_STACK_TRACE_MALLOC; \98 return asan_new_array_aligned(size, static_cast<uptr>(align), &stack)99 100// On OS X it's not enough to just provide our own 'operator new' and101// 'operator delete' implementations, because they're going to be in the102// runtime dylib, and the main executable will depend on both the runtime103// dylib and libstdc++, each of those'll have its implementation of new and104// delete.105// To make sure that C++ allocation/deallocation operators are overridden on106// OS X we need to intercept them using their mangled names.107#if !SANITIZER_APPLE108CXX_OPERATOR_ATTRIBUTE109void *operator new(size_t size) { OPERATOR_NEW_BODY; }110CXX_OPERATOR_ATTRIBUTE111void *operator new[](size_t size) { OPERATOR_NEW_BODY_ARRAY; }112CXX_OPERATOR_ATTRIBUTE113void *operator new(size_t size, std::nothrow_t const &) {114 OPERATOR_NEW_BODY_NOTHROW;115}116CXX_OPERATOR_ATTRIBUTE117void *operator new[](size_t size, std::nothrow_t const &) {118 OPERATOR_NEW_BODY_ARRAY_NOTHROW;119}120CXX_OPERATOR_ATTRIBUTE121void *operator new(size_t size, std::align_val_t align) {122 OPERATOR_NEW_BODY_ALIGN;123}124CXX_OPERATOR_ATTRIBUTE125void *operator new[](size_t size, std::align_val_t align) {126 OPERATOR_NEW_BODY_ALIGN_ARRAY;127}128CXX_OPERATOR_ATTRIBUTE129void *operator new(size_t size, std::align_val_t align,130 std::nothrow_t const &) {131 OPERATOR_NEW_BODY_ALIGN_NOTHROW;132}133CXX_OPERATOR_ATTRIBUTE134void *operator new[](size_t size, std::align_val_t align,135 std::nothrow_t const &) {136 OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW;137}138 139#else // SANITIZER_APPLE140INTERCEPTOR(void *, _Znwm, size_t size) { OPERATOR_NEW_BODY; }141INTERCEPTOR(void *, _Znam, size_t size) { OPERATOR_NEW_BODY_ARRAY; }142INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {143 OPERATOR_NEW_BODY_NOTHROW;144}145INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {146 OPERATOR_NEW_BODY_ARRAY_NOTHROW;147}148#endif // !SANITIZER_APPLE149 150#define OPERATOR_DELETE_BODY \151 GET_STACK_TRACE_FREE; \152 asan_delete(ptr, &stack)153#define OPERATOR_DELETE_BODY_ARRAY \154 GET_STACK_TRACE_FREE; \155 asan_delete_array(ptr, &stack)156#define OPERATOR_DELETE_BODY_ALIGN \157 GET_STACK_TRACE_FREE; \158 asan_delete_aligned(ptr, static_cast<uptr>(align), &stack)159#define OPERATOR_DELETE_BODY_ALIGN_ARRAY \160 GET_STACK_TRACE_FREE; \161 asan_delete_array_aligned(ptr, static_cast<uptr>(align), &stack)162#define OPERATOR_DELETE_BODY_SIZE \163 GET_STACK_TRACE_FREE; \164 asan_delete_sized(ptr, size, &stack)165#define OPERATOR_DELETE_BODY_SIZE_ARRAY \166 GET_STACK_TRACE_FREE; \167 asan_delete_array_sized(ptr, size, &stack)168#define OPERATOR_DELETE_BODY_SIZE_ALIGN \169 GET_STACK_TRACE_FREE; \170 asan_delete_sized_aligned(ptr, size, static_cast<uptr>(align), &stack)171#define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \172 GET_STACK_TRACE_FREE; \173 asan_delete_array_sized_aligned(ptr, size, static_cast<uptr>(align), &stack)174 175#if !SANITIZER_APPLE176CXX_OPERATOR_ATTRIBUTE177void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }178CXX_OPERATOR_ATTRIBUTE179void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY_ARRAY; }180CXX_OPERATOR_ATTRIBUTE181void operator delete(void *ptr, std::nothrow_t const &) {182 OPERATOR_DELETE_BODY;183}184CXX_OPERATOR_ATTRIBUTE185void operator delete[](void *ptr, std::nothrow_t const &) {186 OPERATOR_DELETE_BODY_ARRAY;187}188CXX_OPERATOR_ATTRIBUTE189void operator delete(void *ptr, size_t size) NOEXCEPT {190 OPERATOR_DELETE_BODY_SIZE;191}192CXX_OPERATOR_ATTRIBUTE193void operator delete[](void *ptr, size_t size) NOEXCEPT {194 OPERATOR_DELETE_BODY_SIZE_ARRAY;195}196CXX_OPERATOR_ATTRIBUTE197void operator delete(void *ptr, std::align_val_t align) NOEXCEPT {198 OPERATOR_DELETE_BODY_ALIGN;199}200CXX_OPERATOR_ATTRIBUTE201void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT {202 OPERATOR_DELETE_BODY_ALIGN_ARRAY;203}204CXX_OPERATOR_ATTRIBUTE205void operator delete(void *ptr, std::align_val_t align,206 std::nothrow_t const &) {207 OPERATOR_DELETE_BODY_ALIGN;208}209CXX_OPERATOR_ATTRIBUTE210void operator delete[](void *ptr, std::align_val_t align,211 std::nothrow_t const &) {212 OPERATOR_DELETE_BODY_ALIGN_ARRAY;213}214CXX_OPERATOR_ATTRIBUTE215void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT {216 OPERATOR_DELETE_BODY_SIZE_ALIGN;217}218CXX_OPERATOR_ATTRIBUTE219void operator delete[](void *ptr, size_t size,220 std::align_val_t align) NOEXCEPT {221 OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY;222}223 224#else // SANITIZER_APPLE225INTERCEPTOR(void, _ZdlPv, void *ptr) { OPERATOR_DELETE_BODY; }226INTERCEPTOR(void, _ZdaPv, void *ptr) { OPERATOR_DELETE_BODY_ARRAY; }227INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const &) {228 OPERATOR_DELETE_BODY;229}230INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const &) {231 OPERATOR_DELETE_BODY_ARRAY;232}233#endif // !SANITIZER_APPLE234