diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp index d3c0288285b86..9ebe4d08ec8c1 100644 --- a/compiler-rt/lib/asan/asan_allocator.cpp +++ b/compiler-rt/lib/asan/asan_allocator.cpp @@ -1007,13 +1007,8 @@ void PrintInternalAllocatorStats() { instance.PrintStats(); } -void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { - instance.Deallocate(ptr, 0, 0, stack, alloc_type); -} - -void asan_delete(void *ptr, uptr size, uptr alignment, - BufferedStackTrace *stack, AllocType alloc_type) { - instance.Deallocate(ptr, size, alignment, stack, alloc_type); +void asan_free(void *ptr, BufferedStackTrace *stack) { + instance.Deallocate(ptr, 0, 0, stack, FROM_MALLOC); } void *asan_malloc(uptr size, BufferedStackTrace *stack) { @@ -1068,8 +1063,7 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); } -void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, - AllocType alloc_type) { +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; if (AllocatorMayReturnNull()) @@ -1077,7 +1071,7 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, ReportInvalidAllocationAlignment(alignment, stack); } return SetErrnoOnNull( - instance.Allocate(size, alignment, stack, alloc_type, true)); + instance.Allocate(size, alignment, stack, FROM_MALLOC, true)); } void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { @@ -1117,6 +1111,99 @@ uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) { return usable_size; } +namespace { + +void *asan_new(uptr size, BufferedStackTrace *stack, bool array) { + return SetErrnoOnNull( + instance.Allocate(size, 0, stack, array ? FROM_NEW_BR : FROM_NEW, true)); +} + +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack, + bool array) { + if (UNLIKELY(alignment == 0 || !IsPowerOfTwo(alignment))) { + errno = errno_EINVAL; + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAllocationAlignment(alignment, stack); + } + return SetErrnoOnNull(instance.Allocate( + size, alignment, stack, array ? FROM_NEW_BR : FROM_NEW, true)); +} + +void asan_delete(void *ptr, BufferedStackTrace *stack, bool array) { + instance.Deallocate(ptr, 0, 0, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack, + bool array) { + instance.Deallocate(ptr, 0, alignment, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack, + bool array) { + instance.Deallocate(ptr, size, 0, stack, array ? FROM_NEW_BR : FROM_NEW); +} + +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack, bool array) { + instance.Deallocate(ptr, size, alignment, stack, + array ? FROM_NEW_BR : FROM_NEW); +} + +} // namespace + +void *asan_new(uptr size, BufferedStackTrace *stack) { + return asan_new(size, stack, /*array=*/false); +} + +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack) { + return asan_new_aligned(size, alignment, stack, /*array=*/false); +} + +void *asan_new_array(uptr size, BufferedStackTrace *stack) { + return asan_new(size, stack, /*array=*/true); +} + +void *asan_new_array_aligned(uptr size, uptr alignment, + BufferedStackTrace *stack) { + return asan_new_aligned(size, alignment, stack, /*array=*/true); +} + +void asan_delete(void *ptr, BufferedStackTrace *stack) { + asan_delete(ptr, stack, /*array=*/false); +} + +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack) { + asan_delete_aligned(ptr, alignment, stack, /*array=*/false); +} + +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack) { + asan_delete_sized(ptr, size, stack, /*array=*/false); +} + +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/false); +} + +void asan_delete_array(void *ptr, BufferedStackTrace *stack) { + asan_delete(ptr, stack, /*array=*/true); +} + +void asan_delete_array_aligned(void *ptr, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_aligned(ptr, alignment, stack, /*array=*/true); +} + +void asan_delete_array_sized(void *ptr, uptr size, BufferedStackTrace *stack) { + asan_delete_sized(ptr, size, stack, /*array=*/true); +} + +void asan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack) { + asan_delete_sized_aligned(ptr, size, alignment, stack, /*array=*/true); +} + uptr asan_mz_size(const void *ptr) { return instance.AllocationSize(reinterpret_cast(ptr)); } diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h index 247d8bb77c984..fdf456473fb02 100644 --- a/compiler-rt/lib/asan/asan_allocator.h +++ b/compiler-rt/lib/asan/asan_allocator.h @@ -270,11 +270,8 @@ struct AsanThreadLocalMallocStorage { AsanThreadLocalMallocStorage() {} }; -void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, - AllocType alloc_type); -void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); -void asan_delete(void *ptr, uptr size, uptr alignment, - BufferedStackTrace *stack, AllocType alloc_type); +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack); +void asan_free(void *ptr, BufferedStackTrace *stack); void *asan_malloc(uptr size, BufferedStackTrace *stack); void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); @@ -289,6 +286,23 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack); uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); +void *asan_new(uptr size, BufferedStackTrace *stack); +void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack); +void *asan_new_array(uptr size, BufferedStackTrace *stack); +void *asan_new_array_aligned(uptr size, uptr alignment, + BufferedStackTrace *stack); +void asan_delete(void *ptr, BufferedStackTrace *stack); +void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack); +void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack); +void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack); +void asan_delete_array(void *ptr, BufferedStackTrace *stack); +void asan_delete_array_aligned(void *ptr, uptr alignment, + BufferedStackTrace *stack); +void asan_delete_array_sized(void *ptr, uptr size, BufferedStackTrace *stack); +void asan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment, + BufferedStackTrace *stack); + uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); void asan_mz_force_unlock(); diff --git a/compiler-rt/lib/asan/asan_mac.cpp b/compiler-rt/lib/asan/asan_mac.cpp index be513a03ed5cd..a68e362e07d45 100644 --- a/compiler-rt/lib/asan/asan_mac.cpp +++ b/compiler-rt/lib/asan/asan_mac.cpp @@ -103,6 +103,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { // dispatch_after() // dispatch_group_async_f() // dispatch_group_async() +// dispatch_apply() +// dispatch_apply_f() // TODO(glider): libdispatch API contains other functions that we don't support // yet. // @@ -128,6 +130,7 @@ typedef void* dispatch_queue_t; typedef void* dispatch_source_t; typedef u64 dispatch_time_t; typedef void (*dispatch_function_t)(void *block); +typedef void (*dispatch_apply_function_t)(void *, size_t); typedef void* (*worker_t)(void *block); typedef unsigned long dispatch_mach_reason; typedef void *dispatch_mach_msg_t; @@ -147,7 +150,11 @@ typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason reason, // A wrapper for the ObjC blocks used to support libdispatch. typedef struct { void *block; - dispatch_function_t func; + union { + dispatch_function_t dispatch_func; + dispatch_apply_function_t dispatch_apply_func; + static_assert(sizeof(dispatch_func) == sizeof(dispatch_apply_func)); + }; u32 parent_tid; } asan_block_context_t; @@ -175,8 +182,8 @@ void asan_dispatch_call_block_and_release(void *block) { block, (void*)pthread_self()); asan_register_worker_thread(context->parent_tid, &stack); // Call the original dispatcher for the block. - context->func(context->block); - asan_free(context, &stack, FROM_MALLOC); + context->dispatch_func(context->block); + asan_free(context, &stack); } } // namespace __asan @@ -191,7 +198,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; - asan_ctxt->func = func; + asan_ctxt->dispatch_func = func; asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); return asan_ctxt; } @@ -243,13 +250,34 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, asan_dispatch_call_block_and_release); } -#if !defined(MISSING_BLOCKS_SUPPORT) +extern "C" void asan_dispatch_apply_f_work(void *context, size_t iteration) { + GET_STACK_TRACE_THREAD; + asan_block_context_t *asan_ctxt = (asan_block_context_t *)context; + asan_register_worker_thread(asan_ctxt->parent_tid, &stack); + asan_ctxt->dispatch_apply_func(asan_ctxt->block, iteration); +} + +INTERCEPTOR(void, dispatch_apply_f, size_t iterations, dispatch_queue_t queue, + void *ctxt, dispatch_apply_function_t work) { + GET_STACK_TRACE_THREAD; + asan_block_context_t *asan_ctxt = + (asan_block_context_t *)asan_malloc(sizeof(asan_block_context_t), &stack); + asan_ctxt->block = ctxt; + asan_ctxt->dispatch_apply_func = work; + asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); + REAL(dispatch_apply_f)(iterations, queue, (void *)asan_ctxt, + asan_dispatch_apply_f_work); +} + +# if !defined(MISSING_BLOCKS_SUPPORT) extern "C" { void dispatch_async(dispatch_queue_t dq, void(^work)(void)); void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)); void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)); +void dispatch_apply(size_t iterations, dispatch_queue_t queue, + void (^block)(size_t iteration)); void dispatch_source_set_cancel_handler(dispatch_source_t ds, void(^work)(void)); void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); @@ -332,6 +360,20 @@ INTERCEPTOR(void *, dispatch_mach_create_f, const char *label, }); } -#endif +INTERCEPTOR(void, dispatch_apply, size_t iterations, dispatch_queue_t queue, + void (^block)(size_t iteration)) { + ENABLE_FRAME_POINTER; + int parent_tid = GetCurrentTidOrInvalid(); + + void (^asan_block)(size_t) = ^(size_t iteration) { + GET_STACK_TRACE_THREAD; + asan_register_worker_thread(parent_tid, &stack); + block(iteration); + }; + + REAL(dispatch_apply)(iterations, queue, asan_block); +} + +# endif #endif // SANITIZER_APPLE diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp index 3f023d4c2ed0a..add57318785be 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -49,7 +49,7 @@ INTERCEPTOR(void, free, void *ptr) { if (DlsymAlloc::PointerIsMine(ptr)) return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); } #if SANITIZER_INTERCEPT_CFREE @@ -57,7 +57,7 @@ INTERCEPTOR(void, cfree, void *ptr) { if (DlsymAlloc::PointerIsMine(ptr)) return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); } #endif // SANITIZER_INTERCEPT_CFREE @@ -93,12 +93,12 @@ INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) { #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - return asan_memalign(boundary, size, &stack, FROM_MALLOC); + return asan_memalign(boundary, size, &stack); } INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - return asan_memalign(boundary, size, &stack, FROM_MALLOC); + return asan_memalign(boundary, size, &stack); } #endif // SANITIZER_INTERCEPT_MEMALIGN diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cpp b/compiler-rt/lib/asan/asan_malloc_mac.cpp index f25d7e1901536..a442bdbbaa4d3 100644 --- a/compiler-rt/lib/asan/asan_malloc_mac.cpp +++ b/compiler-rt/lib/asan/asan_malloc_mac.cpp @@ -31,7 +31,7 @@ using namespace __asan; # define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock() # define COMMON_MALLOC_MEMALIGN(alignment, size) \ GET_STACK_TRACE_MALLOC; \ - void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC) + void *p = asan_memalign(alignment, size, &stack) # define COMMON_MALLOC_MALLOC(size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_malloc(size, &stack) @@ -46,10 +46,10 @@ using namespace __asan; int res = asan_posix_memalign(memptr, alignment, size, &stack); # define COMMON_MALLOC_VALLOC(size) \ GET_STACK_TRACE_MALLOC; \ - void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); + void *p = asan_memalign(GetPageSizeCached(), size, &stack); # define COMMON_MALLOC_FREE(ptr) \ GET_STACK_TRACE_FREE; \ - asan_free(ptr, &stack, FROM_MALLOC); + asan_free(ptr, &stack); # define COMMON_MALLOC_SIZE(ptr) uptr size = asan_mz_size(ptr); # define COMMON_MALLOC_FILL_STATS(zone, stats) \ AsanMallocStats malloc_stats; \ diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp index 3278f07219876..8d98da940800f 100644 --- a/compiler-rt/lib/asan/asan_malloc_win.cpp +++ b/compiler-rt/lib/asan/asan_malloc_win.cpp @@ -69,7 +69,7 @@ __declspec(noinline) size_t _msize_base(void *ptr) { return _msize(ptr); } __declspec(noinline) void free(void *ptr) { GET_STACK_TRACE_FREE; - return asan_free(ptr, &stack, FROM_MALLOC); + return asan_free(ptr, &stack); } __declspec(noinline) void _free_dbg(void *ptr, int) { free(ptr); } @@ -252,7 +252,7 @@ INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { CHECK((HEAP_FREE_UNSUPPORTED_FLAGS & dwFlags) != 0 && "unsupported flags"); } GET_STACK_TRACE_FREE; - asan_free(lpMem, &stack, FROM_MALLOC); + asan_free(lpMem, &stack); return true; } @@ -306,7 +306,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc, if (replacement_alloc) { size_t old_size = heapSizeFunc(hHeap, dwFlags, lpMem); if (old_size == ((size_t)0) - 1) { - asan_free(replacement_alloc, &stack, FROM_MALLOC); + asan_free(replacement_alloc, &stack); return nullptr; } REAL(memcpy)(replacement_alloc, lpMem, old_size); @@ -331,7 +331,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc, old_usable_size = asan_malloc_usable_size(lpMem, pc, bp); REAL(memcpy)(replacement_alloc, lpMem, Min(dwBytes, old_usable_size)); - asan_free(lpMem, &stack, FROM_MALLOC); + asan_free(lpMem, &stack); } return replacement_alloc; } @@ -429,7 +429,7 @@ INTERCEPTOR_WINAPI(BOOL, RtlFreeHeap, HANDLE HeapHandle, DWORD Flags, return REAL(RtlFreeHeap)(HeapHandle, Flags, BaseAddress); } GET_STACK_TRACE_FREE; - asan_free(BaseAddress, &stack, FROM_MALLOC); + asan_free(BaseAddress, &stack); return true; } diff --git a/compiler-rt/lib/asan/asan_new_delete.cpp b/compiler-rt/lib/asan/asan_new_delete.cpp index 99c7c9938dfb3..d7ed5b570728b 100644 --- a/compiler-rt/lib/asan/asan_new_delete.cpp +++ b/compiler-rt/lib/asan/asan_new_delete.cpp @@ -60,42 +60,42 @@ enum class align_val_t: size_t {}; // TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. // For local pool allocation, align to SHADOW_GRANULARITY to match asan // allocator behavior. -#define OPERATOR_NEW_BODY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign(0, size, &stack, FROM_NEW); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ +#define OPERATOR_NEW_BODY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new(size, &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign(0, size, &stack, FROM_NEW) -#define OPERATOR_NEW_BODY_ARRAY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign(0, size, &stack, FROM_NEW_BR); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new(size, &stack) +#define OPERATOR_NEW_BODY_ARRAY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_array(size, &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ARRAY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign(0, size, &stack, FROM_NEW_BR) -#define OPERATOR_NEW_BODY_ALIGN \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign((uptr)align, size, &stack, FROM_NEW); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new_array(size, &stack) +#define OPERATOR_NEW_BODY_ALIGN \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_aligned(size, static_cast(align), &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ALIGN_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign((uptr)align, size, &stack, FROM_NEW) -#define OPERATOR_NEW_BODY_ALIGN_ARRAY \ - GET_STACK_TRACE_MALLOC; \ - void *res = asan_memalign((uptr)align, size, &stack, FROM_NEW_BR); \ - if (UNLIKELY(!res)) \ - ReportOutOfMemory(size, &stack); \ + return asan_new_aligned(size, static_cast(align), &stack) +#define OPERATOR_NEW_BODY_ALIGN_ARRAY \ + GET_STACK_TRACE_MALLOC; \ + void *res = asan_new_array_aligned(size, static_cast(align), &stack); \ + if (UNLIKELY(!res)) \ + ReportOutOfMemory(size, &stack); \ return res #define OPERATOR_NEW_BODY_ALIGN_ARRAY_NOTHROW \ GET_STACK_TRACE_MALLOC; \ - return asan_memalign((uptr)align, size, &stack, FROM_NEW_BR) + return asan_new_array_aligned(size, static_cast(align), &stack) // On OS X it's not enough to just provide our own 'operator new' and // 'operator delete' implementations, because they're going to be in the @@ -149,28 +149,28 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { #define OPERATOR_DELETE_BODY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, 0, &stack, FROM_NEW) + asan_delete(ptr, &stack) #define OPERATOR_DELETE_BODY_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, 0, &stack, FROM_NEW_BR) + asan_delete_array(ptr, &stack) #define OPERATOR_DELETE_BODY_ALIGN \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, static_cast(align), &stack, FROM_NEW) + asan_delete_aligned(ptr, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_ALIGN_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, 0, static_cast(align), &stack, FROM_NEW_BR) + asan_delete_array_aligned(ptr, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_SIZE \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, 0, &stack, FROM_NEW) + asan_delete_sized(ptr, size, &stack) #define OPERATOR_DELETE_BODY_SIZE_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, 0, &stack, FROM_NEW_BR) + asan_delete_array_sized(ptr, size, &stack) #define OPERATOR_DELETE_BODY_SIZE_ALIGN \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, static_cast(align), &stack, FROM_NEW) + asan_delete_sized_aligned(ptr, size, static_cast(align), &stack) #define OPERATOR_DELETE_BODY_SIZE_ALIGN_ARRAY \ GET_STACK_TRACE_FREE; \ - asan_delete(ptr, size, static_cast(align), &stack, FROM_NEW_BR) + asan_delete_array_sized_aligned(ptr, size, static_cast(align), &stack) #if !SANITIZER_APPLE CXX_OPERATOR_ATTRIBUTE diff --git a/compiler-rt/lib/asan/tests/asan_mac_test.cpp b/compiler-rt/lib/asan/tests/asan_mac_test.cpp index bd36089991deb..4b21f12f81eac 100644 --- a/compiler-rt/lib/asan/tests/asan_mac_test.cpp +++ b/compiler-rt/lib/asan/tests/asan_mac_test.cpp @@ -116,6 +116,12 @@ TEST(AddressSanitizerMac, GCDDispatchAfter) { EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend"); } +TEST(AddressSanitizerMac, GCDDispatchApply) { + // Make sure the whole ASan report is printed, i.e. that we don't die + // on a CHECK. + EXPECT_DEATH(TestGCDDispatchApply(), "Shadow byte legend"); +} + TEST(AddressSanitizerMac, GCDSourceEvent) { // Make sure the whole ASan report is printed, i.e. that we don't die // on a CHECK. diff --git a/compiler-rt/lib/asan/tests/asan_mac_test.h b/compiler-rt/lib/asan/tests/asan_mac_test.h index 441547a5a3dcb..ec71546a3989b 100644 --- a/compiler-rt/lib/asan/tests/asan_mac_test.h +++ b/compiler-rt/lib/asan/tests/asan_mac_test.h @@ -9,6 +9,7 @@ extern "C" { void TestGCDReuseWqthreadsAsync(); void TestGCDReuseWqthreadsSync(); void TestGCDDispatchAfter(); + void TestGCDDispatchApply(); void TestGCDInTSDDestructor(); void TestGCDSourceEvent(); void TestGCDSourceCancel(); diff --git a/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm b/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm index 3f8fa26d95b8d..ddb50f894639d 100644 --- a/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm +++ b/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm @@ -148,6 +148,16 @@ void TestGCDDispatchAfter() { wait_forever(); } +void TestGCDDispatchApply() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + __block char *buffer = (char *)malloc(4); + dispatch_apply(8, queue, ^(size_t i) { + access_memory(&buffer[i]); + }); + + free(buffer); // not reached +} + void worker_do_deallocate(void *ptr) { free(ptr); } diff --git a/compiler-rt/lib/asan/tests/asan_noinst_test.cpp b/compiler-rt/lib/asan/tests/asan_noinst_test.cpp index f485404758b54..401219ac3628c 100644 --- a/compiler-rt/lib/asan/tests/asan_noinst_test.cpp +++ b/compiler-rt/lib/asan/tests/asan_noinst_test.cpp @@ -71,7 +71,7 @@ static void *MallocStress(void *NumOfItrPtr) { void *ptr = vec[idx]; vec[idx] = vec.back(); vec.pop_back(); - __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC); + __asan::asan_free(ptr, &stack1); } else { size_t size = my_rand_r(&seed) % 1000 + 1; switch ((my_rand_r(&seed) % 128)) { @@ -80,8 +80,7 @@ static void *MallocStress(void *NumOfItrPtr) { case 2: size += 4096; break; } size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); - char *ptr = (char *)__asan::asan_memalign(alignment, size, &stack2, - __asan::FROM_MALLOC); + char *ptr = (char *)__asan::asan_memalign(alignment, size, &stack2); EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0)); vec.push_back(ptr); ptr[0] = 0; @@ -89,8 +88,7 @@ static void *MallocStress(void *NumOfItrPtr) { ptr[size/2] = 0; } } - for (size_t i = 0; i < vec.size(); i++) - __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC); + for (size_t i = 0; i < vec.size(); i++) __asan::asan_free(vec[i], &stack3); return nullptr; } @@ -143,12 +141,12 @@ TEST(AddressSanitizer, QuarantineTest) { const int size = 1024; void *p = __asan::asan_malloc(size, &stack); - __asan::asan_free(p, &stack, __asan::FROM_MALLOC); + __asan::asan_free(p, &stack); size_t i; size_t max_i = 1 << 30; for (i = 0; i < max_i; i++) { void *p1 = __asan::asan_malloc(size, &stack); - __asan::asan_free(p1, &stack, __asan::FROM_MALLOC); + __asan::asan_free(p1, &stack); if (p1 == p) break; } EXPECT_GE(i, 10000U); @@ -165,7 +163,7 @@ void *ThreadedQuarantineTestWorker(void *unused) { for (size_t i = 0; i < 1000; i++) { void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack); - __asan::asan_free(p, &stack, __asan::FROM_MALLOC); + __asan::asan_free(p, &stack); } return NULL; } @@ -204,7 +202,7 @@ void *ThreadedOneSizeMallocStress(void *unused) { p[i] = __asan::asan_malloc(32, &stack); } for (size_t i = 0; i < kNumMallocs; i++) { - __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC); + __asan::asan_free(p[i], &stack); } } return NULL; @@ -260,7 +258,7 @@ static void TestLoadStoreCallbacks(CB cb[2][5]) { } } } - __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC); + __asan::asan_free(ptr, &stack); } __asan_test_only_reported_buggy_pointer = 0; } diff --git a/compiler-rt/test/asan/TestCases/Darwin/dispatch_apply_threadno.c b/compiler-rt/test/asan/TestCases/Darwin/dispatch_apply_threadno.c new file mode 100644 index 0000000000000..5e06615e8e9e9 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Darwin/dispatch_apply_threadno.c @@ -0,0 +1,54 @@ +// Bugs caught within missing GCD dispatch blocks result in thread being reported as T-1 +// with an empty stack. +// This tests that dispatch_apply blocks can capture valid thread number and stack. + +// RUN: %clang_asan %s -o %t +// RUN: not %run %t func 2>&1 | FileCheck %s --check-prefixes=CHECK-FUNC,CHECK +// RUN: not %run %t block 2>&1 | FileCheck %s --check-prefixes=CHECK-BLOCK,CHECK + +#include +#include +#include + +__attribute__((noinline)) void access_memory_frame(char *x) { *x = 0; } + +__attribute__((noinline)) void test_dispatch_apply() { + char *x = (char *)malloc(4); + dispatch_apply(8, dispatch_get_global_queue(0, 0), ^(size_t i) { + access_memory_frame(&x[i]); + }); +} + +typedef struct { + char *data; +} Context; + +void da_func(void *ctx, size_t i) { + Context *c = (Context *)ctx; + access_memory_frame(&c->data[i]); +} + +__attribute__((noinline)) void test_dispatch_apply_f() { + Context *ctx = (Context *)malloc(sizeof(Context)); + ctx->data = (char *)malloc(4); + dispatch_apply_f(8, dispatch_get_global_queue(0, 0), ctx, da_func); +} + +int main(int argc, const char *argv[]) { + if (strcmp(argv[1], "func") == 0) { + fprintf(stderr, "Test dispatch_apply with function\n"); + // CHECK-FUNC: dispatch_apply with function + test_dispatch_apply_f(); + } else if (strcmp(argv[1], "block") == 0) { + fprintf(stderr, "Test dispatch_apply with block\n"); + // CHECK-BLOCK: dispatch_apply with block + test_dispatch_apply(); + } else { + abort(); + } + return 0; +} + +// CHECK: ERROR: AddressSanitizer: heap-buffer-overflow +// CHECK: #0 0x{{.*}} in {{.*}}access_memory_frame +// CHECK-NOT: T-1