diff options
author | Kostya Serebryany <kcc@google.com> | 2014-09-23 17:59:53 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@gcc.gnu.org> | 2014-09-23 17:59:53 +0000 |
commit | 866e32ad336f1698809cc03c48f884379d6b39e0 (patch) | |
tree | dfe8acd36f160811afc54c8eaf16e8160ba8bd70 /libsanitizer/asan | |
parent | e8ee40544aef309d4225852dda191bf0f986f761 (diff) | |
download | gcc-866e32ad336f1698809cc03c48f884379d6b39e0.zip gcc-866e32ad336f1698809cc03c48f884379d6b39e0.tar.gz gcc-866e32ad336f1698809cc03c48f884379d6b39e0.tar.bz2 |
[libsanitizer merge from upstream r218156]
From-SVN: r215527
Diffstat (limited to 'libsanitizer/asan')
31 files changed, 926 insertions, 975 deletions
diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am index fdc2b45..12f20ae 100644 --- a/libsanitizer/asan/Makefile.am +++ b/libsanitizer/asan/Makefile.am @@ -17,7 +17,7 @@ nodist_toolexeclib_HEADERS = libasan_preinit.o asan_files = \ asan_activation.cc \ asan_allocator2.cc \ - asan_dll_thunk.cc \ + asan_debugging.cc \ asan_fake_stack.cc \ asan_globals.cc \ asan_interceptors.cc \ @@ -34,7 +34,9 @@ asan_files = \ asan_stack.cc \ asan_stats.cc \ asan_thread.cc \ - asan_win.cc + asan_win.cc \ + asan_win_dll_thunk.cc \ + asan_win_dynamic_runtime_thunk.cc libasan_la_SOURCES = $(asan_files) libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/lsan/libsanitizer_lsan.la diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in index cae6493..862eec4 100644 --- a/libsanitizer/asan/Makefile.in +++ b/libsanitizer/asan/Makefile.in @@ -89,12 +89,13 @@ libasan_la_DEPENDENCIES = \ $(top_builddir)/lsan/libsanitizer_lsan.la $(am__append_2) \ $(am__append_3) $(am__DEPENDENCIES_1) am__objects_1 = asan_activation.lo asan_allocator2.lo \ - asan_dll_thunk.lo asan_fake_stack.lo asan_globals.lo \ + asan_debugging.lo asan_fake_stack.lo asan_globals.lo \ asan_interceptors.lo asan_linux.lo asan_mac.lo \ asan_malloc_linux.lo asan_malloc_mac.lo asan_malloc_win.lo \ asan_new_delete.lo asan_poisoning.lo asan_posix.lo \ asan_report.lo asan_rtl.lo asan_stack.lo asan_stats.lo \ - asan_thread.lo asan_win.lo + asan_thread.lo asan_win.lo asan_win_dll_thunk.lo \ + asan_win_dynamic_runtime_thunk.lo am_libasan_la_OBJECTS = $(am__objects_1) libasan_la_OBJECTS = $(am_libasan_la_OBJECTS) libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ @@ -275,7 +276,7 @@ nodist_toolexeclib_HEADERS = libasan_preinit.o asan_files = \ asan_activation.cc \ asan_allocator2.cc \ - asan_dll_thunk.cc \ + asan_debugging.cc \ asan_fake_stack.cc \ asan_globals.cc \ asan_interceptors.cc \ @@ -292,7 +293,9 @@ asan_files = \ asan_stack.cc \ asan_stats.cc \ asan_thread.cc \ - asan_win.cc + asan_win.cc \ + asan_win_dll_thunk.cc \ + asan_win_dynamic_runtime_thunk.cc libasan_la_SOURCES = $(asan_files) libasan_la_LIBADD = \ @@ -416,7 +419,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_activation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_dll_thunk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_debugging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_fake_stack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@ @@ -434,6 +437,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stats.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dll_thunk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dynamic_runtime_thunk.Plo@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h index 174a599..567b368 100644 --- a/libsanitizer/asan/asan_allocator.h +++ b/libsanitizer/asan/asan_allocator.h @@ -140,6 +140,8 @@ struct AsanThreadLocalMallocStorage { void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, AllocType alloc_type); void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type); +void asan_sized_free(void *ptr, uptr size, StackTrace *stack, + AllocType alloc_type); void *asan_malloc(uptr size, StackTrace *stack); void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack); diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc index bbc1ff7..78c1ec1 100644 --- a/libsanitizer/asan/asan_allocator2.cc +++ b/libsanitizer/asan/asan_allocator2.cc @@ -19,6 +19,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" @@ -165,23 +166,6 @@ struct AsanChunk: ChunkBase { } return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log)); } - // If we don't use stack depot, we store the alloc/free stack traces - // in the chunk itself. - u32 *AllocStackBeg() { - return (u32*)(Beg() - RZLog2Size(rz_log)); - } - uptr AllocStackSize() { - CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize); - return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32); - } - u32 *FreeStackBeg() { - return (u32*)(Beg() + kChunkHeader2Size); - } - uptr FreeStackSize() { - if (user_requested_size < kChunkHeader2Size) return 0; - uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY); - return (available - kChunkHeader2Size) / sizeof(u32); - } bool AddrIsInside(uptr addr, bool locked_version = false) { return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); } @@ -461,12 +445,17 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, } } -static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) { +static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack, + AllocType alloc_type) { uptr p = reinterpret_cast<uptr>(ptr); if (p == 0) return; uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); + if (delete_size && flags()->new_delete_type_mismatch && + delete_size != m->UsedSize()) { + ReportNewDeleteSizeMismatch(p, delete_size, stack); + } ASAN_FREE_HOOK(ptr); // Must mark the chunk as quarantined before any changes to its metadata. AtomicallySetQuarantineFlag(m, ptr, stack); @@ -493,7 +482,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { // If realloc() races with free(), we may start copying freed memory. // However, we will report racy double-free later anyway. REAL(memcpy)(new_ptr, old_ptr, memcpy_size); - Deallocate(old_ptr, stack, FROM_MALLOC); + Deallocate(old_ptr, 0, stack, FROM_MALLOC); } return new_ptr; } @@ -592,7 +581,12 @@ void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, } void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) { - Deallocate(ptr, stack, alloc_type); + Deallocate(ptr, 0, stack, alloc_type); +} + +void asan_sized_free(void *ptr, uptr size, StackTrace *stack, + AllocType alloc_type) { + Deallocate(ptr, size, stack, alloc_type); } void *asan_malloc(uptr size, StackTrace *stack) { @@ -614,7 +608,7 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) { if (p == 0) return Allocate(size, 8, stack, FROM_MALLOC, true); if (size == 0) { - Deallocate(p, stack, FROM_MALLOC); + Deallocate(p, 0, stack, FROM_MALLOC); return 0; } return Reallocate(p, size, stack); @@ -758,23 +752,23 @@ using namespace __asan; // NOLINT // ASan allocator doesn't reserve extra bytes, so normally we would // just return "size". We don't want to expose our redzone sizes, etc here. -uptr __asan_get_estimated_allocated_size(uptr size) { +uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } -int __asan_get_ownership(const void *p) { +int __sanitizer_get_ownership(const void *p) { uptr ptr = reinterpret_cast<uptr>(p); return (AllocationSize(ptr) > 0); } -uptr __asan_get_allocated_size(const void *p) { +uptr __sanitizer_get_allocated_size(const void *p) { if (p == 0) return 0; uptr ptr = reinterpret_cast<uptr>(p); uptr allocated_size = AllocationSize(ptr); // Die if p is not malloced or if it is already freed. if (allocated_size == 0) { GET_STACK_TRACE_FATAL_HERE; - ReportAsanGetAllocatedSizeNotOwned(ptr, &stack); + ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack); } return allocated_size; } @@ -783,12 +777,12 @@ uptr __asan_get_allocated_size(const void *p) { // Provide default (no-op) implementation of malloc hooks. extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -void __asan_malloc_hook(void *ptr, uptr size) { +void __sanitizer_malloc_hook(void *ptr, uptr size) { (void)ptr; (void)size; } SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -void __asan_free_hook(void *ptr) { +void __sanitizer_free_hook(void *ptr) { (void)ptr; } } // extern "C" diff --git a/libsanitizer/asan/asan_asm_instrumentation.S b/libsanitizer/asan/asan_asm_instrumentation.S deleted file mode 100644 index 36a9d0b..0000000 --- a/libsanitizer/asan/asan_asm_instrumentation.S +++ /dev/null @@ -1,599 +0,0 @@ -// This file was generated by gen_asm_instrumentation.sh. Please, do not edit -.section .text -#if defined(__x86_64__) || defined(__i386__) -.globl __asan_report_store1 -.globl __asan_report_load1 -.globl __asan_report_store2 -.globl __asan_report_load2 -.globl __asan_report_store4 -.globl __asan_report_load4 -.globl __asan_report_store8 -.globl __asan_report_load8 -.globl __asan_report_store16 -.globl __asan_report_load16 -#endif // defined(__x86_64__) || defined(__i386__) -#if defined(__i386__) -// Sanitize 1-byte store. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_store1 -.type __sanitizer_sanitize_store1, @function -__sanitizer_sanitize_store1: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_store1_done - movl %eax, %edx - andl $0x7, %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_store1_done - pushl %eax - cld - emms - call __asan_report_store1@PLT -.sanitize_store1_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 1-byte load. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_load1 -.type __sanitizer_sanitize_load1, @function -__sanitizer_sanitize_load1: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_load1_done - movl %eax, %edx - andl $0x7, %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_load1_done - pushl %eax - cld - emms - call __asan_report_load1@PLT -.sanitize_load1_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 2-byte store. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_store2 -.type __sanitizer_sanitize_store2, @function -__sanitizer_sanitize_store2: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_store2_done - movl %eax, %edx - andl $0x7, %edx - incl %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_store2_done - pushl %eax - cld - emms - call __asan_report_store2@PLT -.sanitize_store2_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 2-byte load. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_load2 -.type __sanitizer_sanitize_load2, @function -__sanitizer_sanitize_load2: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_load2_done - movl %eax, %edx - andl $0x7, %edx - incl %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_load2_done - pushl %eax - cld - emms - call __asan_report_load2@PLT -.sanitize_load2_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 4-byte store. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_store4 -.type __sanitizer_sanitize_store4, @function -__sanitizer_sanitize_store4: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_store4_done - movl %eax, %edx - andl $0x7, %edx - addl $0x3, %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_store4_done - pushl %eax - cld - emms - call __asan_report_store4@PLT -.sanitize_store4_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 4-byte load. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_load4 -.type __sanitizer_sanitize_load4, @function -__sanitizer_sanitize_load4: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - movb 0x20000000(%ecx), %cl - testb %cl, %cl - je .sanitize_load4_done - movl %eax, %edx - andl $0x7, %edx - addl $0x3, %edx - movsbl %cl, %ecx - cmpl %ecx, %edx - jl .sanitize_load4_done - pushl %eax - cld - emms - call __asan_report_load4@PLT -.sanitize_load4_done: - popfl - popl %edx - popl %ecx - popl %eax - leave - ret -// Sanitize 8-byte store. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_store8 -.type __sanitizer_sanitize_store8, @function -__sanitizer_sanitize_store8: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - cmpb $0x0, 0x20000000(%ecx) - je .sanitize_store8_done - pushl %eax - cld - emms - call __asan_report_store8@PLT -.sanitize_store8_done: - popfl - popl %ecx - popl %eax - leave - ret -// Sanitize 8-byte load. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_load8 -.type __sanitizer_sanitize_load8, @function -__sanitizer_sanitize_load8: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - cmpb $0x0, 0x20000000(%ecx) - je .sanitize_load8_done - pushl %eax - cld - emms - call __asan_report_load8@PLT -.sanitize_load8_done: - popfl - popl %ecx - popl %eax - leave - ret -// Sanitize 16-byte store. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_store16 -.type __sanitizer_sanitize_store16, @function -__sanitizer_sanitize_store16: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - cmpw $0x0, 0x20000000(%ecx) - je .sanitize_store16_done - pushl %eax - cld - emms - call __asan_report_store16@PLT -.sanitize_store16_done: - popfl - popl %ecx - popl %eax - leave - ret -// Sanitize 16-byte load. Takes one 4-byte address as an argument on -// stack, nothing is returned. -.globl __sanitizer_sanitize_load16 -.type __sanitizer_sanitize_load16, @function -__sanitizer_sanitize_load16: - pushl %ebp - movl %esp, %ebp - pushl %eax - pushl %ecx - pushfl - movl 8(%ebp), %eax - movl %eax, %ecx - shrl $0x3, %ecx - cmpw $0x0, 0x20000000(%ecx) - je .sanitize_load16_done - pushl %eax - cld - emms - call __asan_report_load16@PLT -.sanitize_load16_done: - popfl - popl %ecx - popl %eax - leave - ret -#endif // defined(__i386__) -#if defined(__x86_64__) -// Sanitize 1-byte store. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_store1 -.type __sanitizer_sanitize_store1, @function -__sanitizer_sanitize_store1: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_store1_done - movl %edi, %ecx - andl $0x7, %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_store1_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_store1@PLT -.sanitize_store1_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 1-byte load. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_load1 -.type __sanitizer_sanitize_load1, @function -__sanitizer_sanitize_load1: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_load1_done - movl %edi, %ecx - andl $0x7, %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_load1_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_load1@PLT -.sanitize_load1_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 2-byte store. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_store2 -.type __sanitizer_sanitize_store2, @function -__sanitizer_sanitize_store2: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_store2_done - movl %edi, %ecx - andl $0x7, %ecx - incl %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_store2_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_store2@PLT -.sanitize_store2_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 2-byte load. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_load2 -.type __sanitizer_sanitize_load2, @function -__sanitizer_sanitize_load2: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_load2_done - movl %edi, %ecx - andl $0x7, %ecx - incl %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_load2_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_load2@PLT -.sanitize_load2_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 4-byte store. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_store4 -.type __sanitizer_sanitize_store4, @function -__sanitizer_sanitize_store4: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_store4_done - movl %edi, %ecx - andl $0x7, %ecx - addl $0x3, %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_store4_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_store4@PLT -.sanitize_store4_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 4-byte load. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_load4 -.type __sanitizer_sanitize_load4, @function -__sanitizer_sanitize_load4: - leaq -128(%rsp), %rsp - pushq %rax - pushq %rcx - pushfq - movq %rdi, %rax - shrq $0x3, %rax - movb 0x7fff8000(%rax), %al - test %al, %al - je .sanitize_load4_done - movl %edi, %ecx - andl $0x7, %ecx - addl $0x3, %ecx - movsbl %al, %eax - cmpl %eax, %ecx - jl .sanitize_load4_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_load4@PLT -.sanitize_load4_done: - popfq - popq %rcx - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 8-byte store. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_store8 -.type __sanitizer_sanitize_store8, @function -__sanitizer_sanitize_store8: - leaq -128(%rsp), %rsp - pushq %rax - pushfq - movq %rdi, %rax - shrq $0x3, %rax - cmpb $0x0, 0x7fff8000(%rax) - je .sanitize_store8_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_store8@PLT -.sanitize_store8_done: - popfq - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 8-byte load. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_load8 -.type __sanitizer_sanitize_load8, @function -__sanitizer_sanitize_load8: - leaq -128(%rsp), %rsp - pushq %rax - pushfq - movq %rdi, %rax - shrq $0x3, %rax - cmpb $0x0, 0x7fff8000(%rax) - je .sanitize_load8_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_load8@PLT -.sanitize_load8_done: - popfq - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 16-byte store. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_store16 -.type __sanitizer_sanitize_store16, @function -__sanitizer_sanitize_store16: - leaq -128(%rsp), %rsp - pushq %rax - pushfq - movq %rdi, %rax - shrq $0x3, %rax - cmpw $0x0, 0x7fff8000(%rax) - je .sanitize_store16_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_store16@PLT -.sanitize_store16_done: - popfq - popq %rax - leaq 128(%rsp), %rsp - ret -// Sanitize 16-byte load. Takes one 8-byte address as an argument in %rdi, -// nothing is returned. -.globl __sanitizer_sanitize_load16 -.type __sanitizer_sanitize_load16, @function -__sanitizer_sanitize_load16: - leaq -128(%rsp), %rsp - pushq %rax - pushfq - movq %rdi, %rax - shrq $0x3, %rax - cmpw $0x0, 0x7fff8000(%rax) - je .sanitize_load16_done - subq $8, %rsp - andq $-16, %rsp - cld - emms - call __asan_report_load16@PLT -.sanitize_load16_done: - popfq - popq %rax - leaq 128(%rsp), %rsp - ret -#endif // defined(__x86_64__) -/* We do not need executable stack. */ -#if defined(__arm__) - .section .note.GNU-stack,"",%progbits -#else - .section .note.GNU-stack,"",@progbits -#endif // defined(__arm__) -#endif // __linux__ diff --git a/libsanitizer/asan/asan_debugging.cc b/libsanitizer/asan/asan_debugging.cc new file mode 100644 index 0000000..302574d --- /dev/null +++ b/libsanitizer/asan/asan_debugging.cc @@ -0,0 +1,72 @@ +//===-- asan_debugging.cc -------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file contains various functions that are generally useful to call when +// using a debugger (LLDB, GDB). +//===----------------------------------------------------------------------===// + +#include "asan_allocator.h" +#include "asan_flags.h" +#include "asan_internal.h" +#include "asan_mapping.h" +#include "asan_thread.h" + +namespace __asan { + +uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id, + bool alloc_stack) { + AsanChunkView chunk = FindHeapChunkByAddress(addr); + if (!chunk.IsValid()) return 0; + + StackTrace stack; + if (alloc_stack) { + if (chunk.AllocTid() == kInvalidTid) return 0; + chunk.GetAllocStack(&stack); + if (thread_id) *thread_id = chunk.AllocTid(); + } else { + if (chunk.FreeTid() == kInvalidTid) return 0; + chunk.GetFreeStack(&stack); + if (thread_id) *thread_id = chunk.FreeTid(); + } + + if (trace && size) { + if (size > kStackTraceMax) + size = kStackTraceMax; + if (size > stack.size) + size = stack.size; + for (uptr i = 0; i < size; i++) + trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]); + + return size; + } + + return 0; +} + +} // namespace __asan + +using namespace __asan; + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { + return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true); +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { + return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) { + if (shadow_scale) + *shadow_scale = SHADOW_SCALE; + if (shadow_offset) + *shadow_offset = SHADOW_OFFSET; +} diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h index 42463a6..2f155eb 100644 --- a/libsanitizer/asan/asan_flags.h +++ b/libsanitizer/asan/asan_flags.h @@ -50,12 +50,13 @@ struct Flags { bool print_stats; bool print_legend; bool atexit; - bool disable_core; bool allow_reexec; bool print_full_thread_history; bool poison_heap; bool poison_partial; + bool poison_array_cookie; bool alloc_dealloc_mismatch; + bool new_delete_type_mismatch; bool strict_memcmp; bool strict_init_order; bool start_deactivated; diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc index 132a564..15c1886 100644 --- a/libsanitizer/asan/asan_globals.cc +++ b/libsanitizer/asan/asan_globals.cc @@ -20,6 +20,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_stackdepot.h" namespace __asan { @@ -43,6 +44,14 @@ typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals; // Lazy-initialized and never deleted. static VectorOfGlobals *dynamic_init_globals; +// We want to remember where a certain range of globals was registered. +struct GlobalRegistrationSite { + u32 stack_id; + Global *g_first, *g_last; +}; +typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector; +static GlobalRegistrationSiteVector *global_registration_site_vector; + ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { FastPoisonShadow(g->beg, g->size_with_redzone, value); } @@ -61,9 +70,14 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) { } static void ReportGlobal(const Global &g, const char *prefix) { - Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", - prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name, + Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", + prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, g.module_name, g.has_dynamic_init); + if (g.location) { + Report(" location (%p): name=%s[%p], %d %d\n", g.location, + g.location->filename, g.location->filename, g.location->line_no, + g.location->column_no); + } } bool DescribeAddressIfGlobal(uptr addr, uptr size) { @@ -79,6 +93,16 @@ bool DescribeAddressIfGlobal(uptr addr, uptr size) { return res; } +u32 FindRegistrationSite(const Global *g) { + CHECK(global_registration_site_vector); + for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { + GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; + if (g >= grs.g_first && g <= grs.g_last) + return grs.stack_id; + } + return 0; +} + // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. @@ -99,7 +123,8 @@ static void RegisterGlobal(const Global *g) { for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { if (g->beg == l->g->beg && (flags()->detect_odr_violation >= 2 || g->size != l->g->size)) - ReportODRViolation(g, l->g); + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); } } } @@ -155,7 +180,18 @@ using namespace __asan; // NOLINT // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; + GET_STACK_TRACE_FATAL_HERE; + u32 stack_id = StackDepotPut(stack.trace, stack.size); BlockingMutexLock lock(&mu_for_globals); + if (!global_registration_site_vector) + global_registration_site_vector = + new(allocator_for_globals) GlobalRegistrationSiteVector(128); + GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; + global_registration_site_vector->push_back(site); + if (flags()->report_globals >= 2) { + PRINT_CURRENT_STACK(); + Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); + } for (uptr i = 0; i < n; i++) { RegisterGlobal(&globals[i]); } diff --git a/libsanitizer/asan/asan_init_version.h b/libsanitizer/asan/asan_init_version.h new file mode 100644 index 0000000..da23251 --- /dev/null +++ b/libsanitizer/asan/asan_init_version.h @@ -0,0 +1,30 @@ +//===-- asan_init_version.h -------------------------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This header defines a versioned __asan_init function to be called at the +// startup of the instrumented program. +//===----------------------------------------------------------------------===// +#ifndef ASAN_INIT_VERSION_H +#define ASAN_INIT_VERSION_H + +extern "C" { + // Every time the ASan ABI changes we also change the version number in the + // __asan_init function name. Objects built with incompatible ASan ABI + // versions will not link with run-time. + // Changes between ABI versions: + // v1=>v2: added 'module_name' to __asan_global + // v2=>v3: stack frame description (created by the compiler) + // contains the function PC as the 3-rd field (see + // DescribeAddressIfStack). + // v3=>v4: added '__asan_global_source_location' to __asan_global. + #define __asan_init __asan_init_v4 + #define __asan_init_name "__asan_init_v4" +} + +#endif // ASAN_INIT_VERSION_H diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc index 13deab5..182b784 100644 --- a/libsanitizer/asan/asan_interceptors.cc +++ b/libsanitizer/asan/asan_interceptors.cc @@ -144,6 +144,9 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping() +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping() +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) #include "sanitizer_common/sanitizer_common_interceptors.inc" #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s) @@ -291,37 +294,29 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif -// intercept mlock and friends. -// Since asan maps 16T of RAM, mlock is completely unfriendly to asan. -// All functions return 0 (success). -static void MlockIsUnsupported() { - static bool printed = false; - if (printed) return; - printed = true; - VPrintf(1, - "INFO: AddressSanitizer ignores " - "mlock/mlockall/munlock/munlockall\n"); -} - -INTERCEPTOR(int, mlock, const void *addr, uptr len) { - MlockIsUnsupported(); - return 0; -} - -INTERCEPTOR(int, munlock, const void *addr, uptr len) { - MlockIsUnsupported(); - return 0; +#if SANITIZER_WINDOWS +INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { + CHECK(REAL(RaiseException)); + __asan_handle_no_return(); + REAL(RaiseException)(a, b, c, d); } -INTERCEPTOR(int, mlockall, int flags) { - MlockIsUnsupported(); - return 0; +INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler3)); + __asan_handle_no_return(); + return REAL(_except_handler3)(a, b, c, d); } -INTERCEPTOR(int, munlockall, void) { - MlockIsUnsupported(); - return 0; +#if ASAN_DYNAMIC +// This handler is named differently in -MT and -MD CRTs. +#define _except_handler4 _except_handler4_common +#endif +INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler4)); + __asan_handle_no_return(); + return REAL(_except_handler4)(a, b, c, d); } +#endif static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; @@ -523,7 +518,7 @@ INTERCEPTOR(char*, strdup, const char *s) { } #endif -INTERCEPTOR(uptr, strlen, const char *s) { +INTERCEPTOR(SIZE_T, strlen, const char *s) { if (UNLIKELY(!asan_inited)) return internal_strlen(s); // strlen is called from malloc_default_purgeable_zone() // in __asan::ReplaceSystemAlloc() on Mac. @@ -531,15 +526,15 @@ INTERCEPTOR(uptr, strlen, const char *s) { return REAL(strlen)(s); } ENSURE_ASAN_INITED(); - uptr length = REAL(strlen)(s); + SIZE_T length = REAL(strlen)(s); if (flags()->replace_str) { ASAN_READ_RANGE(s, length + 1); } return length; } -INTERCEPTOR(uptr, wcslen, const wchar_t *s) { - uptr length = REAL(wcslen)(s); +INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { + SIZE_T length = REAL(wcslen)(s); if (!asan_init_is_running) { ENSURE_ASAN_INITED(); ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t)); @@ -691,6 +686,16 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, } #endif // ASAN_INTERCEPT___CXA_ATEXIT +#if ASAN_INTERCEPT_FORK +INTERCEPTOR(int, fork, void) { + ENSURE_ASAN_INITED(); + if (common_flags()->coverage) CovBeforeFork(); + int pid = REAL(fork)(); + if (common_flags()->coverage) CovAfterFork(pid); + return pid; +} +#endif // ASAN_INTERCEPT_FORK + #if SANITIZER_WINDOWS INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, @@ -712,6 +717,9 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread, namespace __asan { void InitializeWindowsInterceptors() { ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(RaiseException); + ASAN_INTERCEPT_FUNC(_except_handler3); + ASAN_INTERCEPT_FUNC(_except_handler4); } } // namespace __asan @@ -759,14 +767,6 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strtoll); #endif -#if ASAN_INTERCEPT_MLOCKX - // Intercept mlock/munlock. - ASAN_INTERCEPT_FUNC(mlock); - ASAN_INTERCEPT_FUNC(munlock); - ASAN_INTERCEPT_FUNC(mlockall); - ASAN_INTERCEPT_FUNC(munlockall); -#endif - // Intecept signal- and jump-related functions. ASAN_INTERCEPT_FUNC(longjmp); #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION @@ -789,7 +789,7 @@ void InitializeAsanInterceptors() { // Intercept exception handling functions. #if ASAN_INTERCEPT___CXA_THROW - INTERCEPT_FUNCTION(__cxa_throw); + ASAN_INTERCEPT_FUNC(__cxa_throw); #endif // Intercept threading-related functions @@ -802,6 +802,10 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(__cxa_atexit); #endif +#if ASAN_INTERCEPT_FORK + ASAN_INTERCEPT_FUNC(fork); +#endif + // Some Windows-specific interceptors. #if SANITIZER_WINDOWS InitializeWindowsInterceptors(); diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h index af7cdc8..95a75db 100644 --- a/libsanitizer/asan/asan_interceptors.h +++ b/libsanitizer/asan/asan_interceptors.h @@ -24,14 +24,14 @@ # define ASAN_INTERCEPT_STRDUP 1 # define ASAN_INTERCEPT_INDEX 1 # define ASAN_INTERCEPT_PTHREAD_CREATE 1 -# define ASAN_INTERCEPT_MLOCKX 1 +# define ASAN_INTERCEPT_FORK 1 #else # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0 # define ASAN_INTERCEPT__LONGJMP 0 # define ASAN_INTERCEPT_STRDUP 0 # define ASAN_INTERCEPT_INDEX 0 # define ASAN_INTERCEPT_PTHREAD_CREATE 0 -# define ASAN_INTERCEPT_MLOCKX 0 +# define ASAN_INTERCEPT_FORK 0 #endif #if SANITIZER_FREEBSD || SANITIZER_LINUX @@ -64,7 +64,9 @@ # define ASAN_INTERCEPT_SIGLONGJMP 0 #endif -#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS +// Android bug: https://code.google.com/p/android/issues/detail?id=61799 +#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \ + !(SANITIZER_ANDROID && defined(__i386)) # define ASAN_INTERCEPT___CXA_THROW 1 #else # define ASAN_INTERCEPT___CXA_THROW 0 @@ -80,7 +82,7 @@ DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size) DECLARE_REAL(void*, memset, void *block, int c, uptr size) DECLARE_REAL(char*, strchr, const char *str, int c) -DECLARE_REAL(uptr, strlen, const char *s) +DECLARE_REAL(SIZE_T, strlen, const char *s) DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size) DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen) DECLARE_REAL(char*, strstr, const char *s1, const char *s2) diff --git a/libsanitizer/asan/asan_interface_internal.h b/libsanitizer/asan/asan_interface_internal.h index 1940477..1a3b33f 100644 --- a/libsanitizer/asan/asan_interface_internal.h +++ b/libsanitizer/asan/asan_interface_internal.h @@ -15,21 +15,24 @@ #include "sanitizer_common/sanitizer_internal_defs.h" +#include "asan_init_version.h" + using __sanitizer::uptr; extern "C" { // This function should be called at the very beginning of the process, // before any instrumented code is executed and before any call to malloc. - // Every time the asan ABI changes we also change the version number in this - // name. Objects build with incompatible asan ABI version - // will not link with run-time. - // Changes between ABI versions: - // v1=>v2: added 'module_name' to __asan_global - // v2=>v3: stack frame description (created by the compiler) - // contains the function PC as the 3-rd field (see - // DescribeAddressIfStack). - SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3(); - #define __asan_init __asan_init_v3 + // Please note that __asan_init is a macro that is replaced with + // __asan_init_vXXX at compile-time. + SANITIZER_INTERFACE_ATTRIBUTE void __asan_init(); + + // This structure is used to describe the source location of a place where + // global was defined. + struct __asan_global_source_location { + const char *filename; + int line_no; + int column_no; + }; // This structure describes an instrumented global variable. struct __asan_global { @@ -40,6 +43,8 @@ extern "C" { const char *module_name; // Module name as a C string. This pointer is a // unique identifier of a module. uptr has_dynamic_init; // Non-zero if the global has dynamic initializer. + __asan_global_source_location *location; // Source location of a global, + // or NULL if it is unknown. }; // These two functions should be called by the instrumented code. @@ -84,6 +89,17 @@ extern "C" { void __asan_describe_address(uptr addr); SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, + u32 *thread_id); + + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, + u32 *thread_id); + + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset); + + SANITIZER_INTERFACE_ATTRIBUTE void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, uptr access_size); @@ -97,25 +113,11 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ void __asan_on_error(); - SANITIZER_INTERFACE_ATTRIBUTE - uptr __asan_get_estimated_allocated_size(uptr size); - - SANITIZER_INTERFACE_ATTRIBUTE int __asan_get_ownership(const void *p); - SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p); - SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes(); - SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size(); - SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes(); - SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ const char* __asan_default_options(); - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size); - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - /* OPTIONAL */ void __asan_free_hook(void *ptr); - // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return SANITIZER_INTERFACE_ATTRIBUTE extern int __asan_option_detect_stack_use_after_return; @@ -142,6 +144,11 @@ extern "C" { void* __asan_memset(void *s, int c, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memmove(void* dest, const void* src, uptr n); + + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_poison_cxx_array_cookie(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_load_cxx_array_cookie(uptr *p); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index d56943a..9473bf6 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -43,10 +43,6 @@ # endif #endif -#ifndef ASAN_USE_PREINIT_ARRAY -# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID) -#endif - #ifndef ASAN_DYNAMIC # ifdef PIC # define ASAN_DYNAMIC 1 @@ -96,6 +92,8 @@ void AppendToErrorMessageBuffer(const char *buffer); void ParseExtraActivationFlags(); +void *AsanDlSymNext(const char *sym); + // Platform-specific options. #if SANITIZER_MAC bool PlatformHasDifferentMemcpyAndMemmove(); @@ -108,9 +106,9 @@ bool PlatformHasDifferentMemcpyAndMemmove(); // Add convenient macro for interface functions that may be represented as // weak hooks. #define ASAN_MALLOC_HOOK(ptr, size) \ - if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size) + if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size) #define ASAN_FREE_HOOK(ptr) \ - if (&__asan_free_hook) __asan_free_hook(ptr) + if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr) #define ASAN_ON_ERROR() \ if (&__asan_on_error) __asan_on_error() @@ -134,6 +132,7 @@ const int kAsanContiguousContainerOOBMagic = 0xfc; const int kAsanStackUseAfterScopeMagic = 0xf8; const int kAsanGlobalRedzoneMagic = 0xf9; const int kAsanInternalHeapMagic = 0xfe; +const int kAsanArrayCookieMagic = 0xac; static const uptr kCurrentStackFrameMagic = 0x41B58AB3; static const uptr kRetiredStackFrameMagic = 0x45E0360E; diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc index 08d2885..c504168 100644 --- a/libsanitizer/asan/asan_linux.cc +++ b/libsanitizer/asan/asan_linux.cc @@ -17,6 +17,7 @@ #include "asan_internal.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_freebsd.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" @@ -25,6 +26,7 @@ #include <sys/mman.h> #include <sys/syscall.h> #include <sys/types.h> +#include <dlfcn.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> @@ -40,19 +42,14 @@ extern "C" void* _DYNAMIC; #else #include <sys/ucontext.h> -#include <dlfcn.h> #include <link.h> #endif -// x86_64 FreeBSD 9.2 and older define 64-bit register names in both 64-bit -// and 32-bit modes. -#if SANITIZER_FREEBSD -#include <sys/param.h> -# if __FreeBSD_version <= 902001 // v9.2 -# define mc_eip mc_rip -# define mc_ebp mc_rbp -# define mc_esp mc_rsp -# endif +// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in +// 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ + __FreeBSD_version <= 902001 // v9.2 +#define ucontext_t xucontext_t #endif typedef enum { @@ -241,6 +238,10 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) { } #endif +void *AsanDlSymNext(const char *sym) { + return dlsym(RTLD_NEXT, sym); +} + } // namespace __asan #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc index 4a295e0..e4c71ce 100644 --- a/libsanitizer/asan/asan_mac.cc +++ b/libsanitizer/asan/asan_mac.cc @@ -372,32 +372,44 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); work(); \ } +// Forces the compiler to generate a frame pointer in the function. +#define ENABLE_FRAME_POINTER \ + do { \ + volatile uptr enable_fp; \ + enable_fp = GET_CURRENT_FRAME(); \ + } while (0) + INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void(^work)(void)) { + ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_async)(dq, asan_block); } INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { + ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_group_async)(dg, dq, asan_block); } INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { + ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_after)(when, queue, asan_block); } INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, void(^work)(void)) { + ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_cancel_handler)(ds, asan_block); } INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, void(^work)(void)) { + ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_event_handler)(ds, asan_block); } diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc index ba908e3..d03f1bb 100644 --- a/libsanitizer/asan/asan_malloc_linux.cc +++ b/libsanitizer/asan/asan_malloc_linux.cc @@ -21,41 +21,6 @@ #include "asan_internal.h" #include "asan_stack.h" -#if SANITIZER_ANDROID -DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size) -DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) -DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) -DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size) -DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size) - -struct MallocDebug { - void* (*malloc)(uptr bytes); - void (*free)(void* mem); - void* (*calloc)(uptr n_elements, uptr elem_size); - void* (*realloc)(void* oldMem, uptr bytes); - void* (*memalign)(uptr alignment, uptr bytes); -}; - -const MallocDebug asan_malloc_dispatch ALIGNED(32) = { - WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign) -}; - -extern "C" const MallocDebug* __libc_malloc_dispatch; - -namespace __asan { -void ReplaceSystemMalloc() { - __libc_malloc_dispatch = &asan_malloc_dispatch; -} -} // namespace __asan - -#else // ANDROID - -namespace __asan { -void ReplaceSystemMalloc() { -} -} // namespace __asan -#endif // ANDROID - // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT @@ -100,6 +65,11 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { return asan_memalign(boundary, size, &stack, FROM_MALLOC); } +INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { + GET_STACK_TRACE_MALLOC; + return asan_memalign(boundary, size, &stack, FROM_MALLOC); +} + INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); @@ -151,4 +121,64 @@ INTERCEPTOR(void, malloc_stats, void) { __asan_print_accumulated_stats(); } +#if SANITIZER_ANDROID +// Format of __libc_malloc_dispatch has changed in Android L. +// While we are moving towards a solution that does not depend on bionic +// internals, here is something to support both K* and L releases. +struct MallocDebugK { + void *(*malloc)(uptr bytes); + void (*free)(void *mem); + void *(*calloc)(uptr n_elements, uptr elem_size); + void *(*realloc)(void *oldMem, uptr bytes); + void *(*memalign)(uptr alignment, uptr bytes); + uptr (*malloc_usable_size)(void *mem); +}; + +struct MallocDebugL { + void *(*calloc)(uptr n_elements, uptr elem_size); + void (*free)(void *mem); + fake_mallinfo (*mallinfo)(void); + void *(*malloc)(uptr bytes); + uptr (*malloc_usable_size)(void *mem); + void *(*memalign)(uptr alignment, uptr bytes); + int (*posix_memalign)(void **memptr, uptr alignment, uptr size); + void* (*pvalloc)(uptr size); + void *(*realloc)(void *oldMem, uptr bytes); + void* (*valloc)(uptr size); +}; + +ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = { + WRAP(malloc), WRAP(free), WRAP(calloc), + WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; + +ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = { + WRAP(calloc), WRAP(free), WRAP(mallinfo), + WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign), + WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc), + WRAP(valloc)}; + +namespace __asan { +void ReplaceSystemMalloc() { + void **__libc_malloc_dispatch_p = + (void **)AsanDlSymNext("__libc_malloc_dispatch"); + if (__libc_malloc_dispatch_p) { + // Decide on K vs L dispatch format by the presence of + // __libc_malloc_default_dispatch export in libc. + void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch"); + if (default_dispatch_p) + *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k; + else + *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l; + } +} +} // namespace __asan + +#else // SANITIZER_ANDROID + +namespace __asan { +void ReplaceSystemMalloc() { +} +} // namespace __asan +#endif // SANITIZER_ANDROID + #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc index 8463d5e..bbcf80e 100644 --- a/libsanitizer/asan/asan_malloc_win.cc +++ b/libsanitizer/asan/asan_malloc_win.cc @@ -21,71 +21,77 @@ #include <stddef.h> -// ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT -// FIXME: Simply defining functions with the same signature in *.obj -// files overrides the standard functions in *.lib -// This works well for simple helloworld-like tests but might need to be -// revisited in the future. +// MT: Simply defining functions with the same signature in *.obj +// files overrides the standard functions in the CRT. +// MD: Memory allocation functions are defined in the CRT .dll, +// so we have to intercept them before they are called for the first time. + +#if ASAN_DYNAMIC +# define ALLOCATION_FUNCTION_ATTRIBUTE +#else +# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +#endif extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void free(void *ptr) { GET_STACK_TRACE_FREE; return asan_free(ptr, &stack, FROM_MALLOC); } -SANITIZER_INTERFACE_ATTRIBUTE -void _free_dbg(void* ptr, int) { +ALLOCATION_FUNCTION_ATTRIBUTE +void _free_dbg(void *ptr, int) { free(ptr); } +ALLOCATION_FUNCTION_ATTRIBUTE void cfree(void *ptr) { - CHECK(!"cfree() should not be used on Windows?"); + CHECK(!"cfree() should not be used on Windows"); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *malloc(size_t size) { GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } -SANITIZER_INTERFACE_ATTRIBUTE -void* _malloc_dbg(size_t size, int , const char*, int) { +ALLOCATION_FUNCTION_ATTRIBUTE +void *_malloc_dbg(size_t size, int, const char *, int) { return malloc(size); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *calloc(size_t nmemb, size_t size) { GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } -SANITIZER_INTERFACE_ATTRIBUTE -void* _calloc_dbg(size_t n, size_t size, int, const char*, int) { - return calloc(n, size); +ALLOCATION_FUNCTION_ATTRIBUTE +void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) { + return calloc(nmemb, size); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { return calloc(nmemb, size); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *realloc(void *ptr, size_t size) { GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *_realloc_dbg(void *ptr, size_t size, int) { CHECK(!"_realloc_dbg should not exist!"); return 0; } -SANITIZER_INTERFACE_ATTRIBUTE -void* _recalloc(void* p, size_t n, size_t elem_size) { +ALLOCATION_FUNCTION_ATTRIBUTE +void *_recalloc(void *p, size_t n, size_t elem_size) { if (!p) return calloc(n, elem_size); const size_t size = n * elem_size; @@ -94,23 +100,23 @@ void* _recalloc(void* p, size_t n, size_t elem_size) { return realloc(p, size); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE size_t _msize(void *ptr) { GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(ptr, pc, bp); } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *_expand(void *memblock, size_t size) { // _expand is used in realloc-like functions to resize the buffer if possible. // We don't want memory to stand still while resizing buffers, so return 0. return 0; } -SANITIZER_INTERFACE_ATTRIBUTE +ALLOCATION_FUNCTION_ATTRIBUTE void *_expand_dbg(void *memblock, size_t size) { - return 0; + return _expand(memblock, size); } // TODO(timurrrr): Might want to add support for _aligned_* allocation @@ -131,37 +137,38 @@ int _CrtSetReportMode(int, int) { } } // extern "C" -using __interception::GetRealFunctionAddress; - -// We don't want to include "windows.h" in this file to avoid extra attributes -// set on malloc/free etc (e.g. dllimport), so declare a few things manually: -extern "C" int __stdcall VirtualProtect(void* addr, size_t size, - DWORD prot, DWORD *old_prot); -const int PAGE_EXECUTE_READWRITE = 0x40; - namespace __asan { void ReplaceSystemMalloc() { -#if defined(_DLL) -# ifdef _WIN64 -# error ReplaceSystemMalloc was not tested on x64 -# endif - char *crt_malloc; - if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) { - // Replace malloc in the CRT dll with a jump to our malloc. - DWORD old_prot, unused; - CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot)); - REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case. - - ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5; - crt_malloc[0] = 0xE9; // jmp, should be followed by an offset. - REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset)); - - CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused)); - - // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64. - } - - // FIXME: investigate whether anything else is needed. +#if defined(ASAN_DYNAMIC) + // We don't check the result because CRT might not be used in the process. + __interception::OverrideFunction("free", (uptr)free); + __interception::OverrideFunction("malloc", (uptr)malloc); + __interception::OverrideFunction("_malloc_crt", (uptr)malloc); + __interception::OverrideFunction("calloc", (uptr)calloc); + __interception::OverrideFunction("_calloc_crt", (uptr)calloc); + __interception::OverrideFunction("realloc", (uptr)realloc); + __interception::OverrideFunction("_realloc_crt", (uptr)realloc); + __interception::OverrideFunction("_recalloc", (uptr)_recalloc); + __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc); + __interception::OverrideFunction("_msize", (uptr)_msize); + __interception::OverrideFunction("_expand", (uptr)_expand); + + // Override different versions of 'operator new' and 'operator delete'. + // No need to override the nothrow versions as they just wrap the throw + // versions. + // FIXME: Unfortunately, MSVC miscompiles the statements that take the + // addresses of the array versions of these operators, + // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992 + // We might want to try to work around this by [inline] assembly or compiling + // parts of the RTL with Clang. + void *(*op_new)(size_t sz) = operator new; + void (*op_delete)(void *p) = operator delete; + void *(*op_array_new)(size_t sz) = operator new[]; + void (*op_array_delete)(void *p) = operator delete[]; + __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new); + __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete); + __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new); + __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete); #endif } } // namespace __asan diff --git a/libsanitizer/asan/asan_new_delete.cc b/libsanitizer/asan/asan_new_delete.cc index a1ab2cd..9d6660e 100644 --- a/libsanitizer/asan/asan_new_delete.cc +++ b/libsanitizer/asan/asan_new_delete.cc @@ -18,6 +18,13 @@ #include <stddef.h> +// C++ operators can't have visibility attributes on Windows. +#if SANITIZER_WINDOWS +# define CXX_OPERATOR_ATTRIBUTE +#else +# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE +#endif + using namespace __asan; // NOLINT // This code has issues on OSX. @@ -49,14 +56,14 @@ struct nothrow_t {}; #endif // __FreeBSD_version #endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(FROM_NEW_BR); } @@ -80,22 +87,32 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { asan_free(ptr, &stack, type); #if !SANITIZER_MAC -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY(FROM_NEW); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY(FROM_NEW_BR); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW); } -INTERCEPTOR_ATTRIBUTE +CXX_OPERATOR_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(FROM_NEW_BR); } +CXX_OPERATOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) throw() { + GET_STACK_TRACE_FREE; + asan_sized_free(ptr, size, &stack, FROM_NEW); +} +CXX_OPERATOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) throw() { + GET_STACK_TRACE_FREE; + asan_sized_free(ptr, size, &stack, FROM_NEW_BR); +} #else // SANITIZER_MAC INTERCEPTOR(void, _ZdlPv, void *ptr) { diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc index a532c5c..65f6cf0 100644 --- a/libsanitizer/asan/asan_poisoning.cc +++ b/libsanitizer/asan/asan_poisoning.cc @@ -225,6 +225,35 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) { *p = x; } +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __asan_poison_cxx_array_cookie(uptr p) { + if (SANITIZER_WORDSIZE != 64) return; + if (!flags()->poison_array_cookie) return; + uptr s = MEM_TO_SHADOW(p); + *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic; +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +uptr __asan_load_cxx_array_cookie(uptr *p) { + if (SANITIZER_WORDSIZE != 64) return *p; + if (!flags()->poison_array_cookie) return *p; + uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p)); + u8 sval = *reinterpret_cast<u8*>(s); + if (sval == kAsanArrayCookieMagic) return *p; + // If sval is not kAsanArrayCookieMagic it can only be freed memory, + // which means that we are going to get double-free. So, return 0 to avoid + // infinite loop of destructors. We don't want to report a double-free here + // though, so print a warning just in case. + // CHECK_EQ(sval, kAsanHeapFreeMagic); + if (sval == kAsanHeapFreeMagic) { + Report("AddressSanitizer: loaded array cookie from free-d memory; " + "expect a double-free report\n"); + return 0; + } + // FIXME: apparently it can be something else; need to find a reproducer. + return *p; +} + // This is a simplified version of __asan_(un)poison_memory_region, which // assumes that left border of region to be poisoned is properly aligned. static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h index 326d9ba..9644b7d 100644 --- a/libsanitizer/asan/asan_poisoning.h +++ b/libsanitizer/asan/asan_poisoning.h @@ -33,7 +33,6 @@ void PoisonShadowPartialRightRedzone(uptr addr, ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, u8 value) { DCHECK(flags()->poison_heap); - uptr PageSize = GetPageSizeCached(); uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); uptr shadow_end = MEM_TO_SHADOW( aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; @@ -46,8 +45,9 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { - uptr page_beg = RoundUpTo(shadow_beg, PageSize); - uptr page_end = RoundDownTo(shadow_end, PageSize); + uptr page_size = GetPageSizeCached(); + uptr page_beg = RoundUpTo(shadow_beg, page_size); + uptr page_end = RoundDownTo(shadow_end, page_size); if (page_beg >= page_end) { REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc index 8f3798a..4eabb74 100644 --- a/libsanitizer/asan/asan_posix.cc +++ b/libsanitizer/asan/asan_posix.cc @@ -48,7 +48,7 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(pc, sp, bp, context, addr); else - ReportSIGSEGV(pc, sp, bp, context, addr); + ReportSIGSEGV("SEGV", pc, sp, bp, context, addr); } // ---------------------- TSD ---------------- {{{1 diff --git a/libsanitizer/asan/asan_preinit.cc b/libsanitizer/asan/asan_preinit.cc index 3104240..2ce1fb9 100644 --- a/libsanitizer/asan/asan_preinit.cc +++ b/libsanitizer/asan/asan_preinit.cc @@ -8,22 +8,12 @@ // This file is a part of AddressSanitizer, an address sanity checker. // // Call __asan_init at the very early stage of process startup. -// On Linux we use .preinit_array section (unless PIC macro is defined). //===----------------------------------------------------------------------===// #include "asan_internal.h" -#if ASAN_USE_PREINIT_ARRAY && !defined(PIC) - // On Linux, we force __asan_init to be called before anyone else - // by placing it into .preinit_array section. - // FIXME: do we have anything like this on Mac? +#if SANITIZER_CAN_USE_PREINIT_ARRAY // The symbol is called __local_asan_preinit, because it's not intended to be // exported. __attribute__((section(".preinit_array"), used)) void (*__local_asan_preinit)(void) = __asan_init; -#elif SANITIZER_WINDOWS && defined(_DLL) - // On Windows, when using dynamic CRT (/MD), we can put a pointer - // to __asan_init into the global list of C initializers. - // See crt0dat.c in the CRT sources for the details. - #pragma section(".CRT$XIB", long, read) // NOLINT - __declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init; #endif diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc index d0a89b9..05622a1 100644 --- a/libsanitizer/asan/asan_report.cc +++ b/libsanitizer/asan/asan_report.cc @@ -57,6 +57,7 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { switch (byte) { case kAsanHeapLeftRedzoneMagic: case kAsanHeapRightRedzoneMagic: + case kAsanArrayCookieMagic: return Red(); case kAsanHeapFreeMagic: return Magenta(); @@ -141,6 +142,8 @@ static void PrintLegend(InternalScopedString *str) { kAsanUserPoisonedMemoryMagic); PrintShadowByte(str, " Container overflow: ", kAsanContiguousContainerOOBMagic); + PrintShadowByte(str, " Array cookie: ", + kAsanArrayCookieMagic); PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); } @@ -195,7 +198,7 @@ static const char *MaybeDemangleGlobalName(const char *name) { else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?') should_demangle = true; - return should_demangle ? Symbolizer::Get()->Demangle(name) : name; + return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name; } // Check if the global is a zero-terminated ASCII string. If so, print it. @@ -210,6 +213,26 @@ static void PrintGlobalNameIfASCII(InternalScopedString *str, (char *)g.beg); } +static const char *GlobalFilename(const __asan_global &g) { + const char *res = g.module_name; + // Prefer the filename from source location, if is available. + if (g.location) + res = g.location->filename; + CHECK(res); + return res; +} + +static void PrintGlobalLocation(InternalScopedString *str, + const __asan_global &g) { + str->append("%s", GlobalFilename(g)); + if (!g.location) + return; + if (g.location->line_no) + str->append(":%d", g.location->line_no); + if (g.location->column_no) + str->append(":%d", g.location->column_no); +} + bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, const __asan_global &g) { static const uptr kMinimalDistanceFromAnotherGlobal = 64; @@ -230,8 +253,10 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, // Can it happen? str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); } - str.append(" of global variable '%s' from '%s' (0x%zx) of size %zu\n", - MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size); + str.append(" of global variable '%s' defined in '", + MaybeDemangleGlobalName(g.name)); + PrintGlobalLocation(&str, g); + str.append("' (0x%zx) of size %zu\n", g.beg, g.size); str.append("%s", d.EndLocation()); PrintGlobalNameIfASCII(&str, g); Printf("%s", str.data()); @@ -317,12 +342,27 @@ void PrintAccessAndVarIntersection(const char *var_name, Printf("%s", str.data()); } -struct StackVarDescr { - uptr beg; - uptr size; - const char *name_pos; - uptr name_len; -}; +bool ParseFrameDescription(const char *frame_descr, + InternalMmapVector<StackVarDescr> *vars) { + char *p; + uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); + CHECK_GT(n_objects, 0); + + for (uptr i = 0; i < n_objects; i++) { + uptr beg = (uptr)internal_simple_strtoll(p, &p, 10); + uptr size = (uptr)internal_simple_strtoll(p, &p, 10); + uptr len = (uptr)internal_simple_strtoll(p, &p, 10); + if (beg == 0 || size == 0 || *p != ' ') { + return false; + } + p++; + StackVarDescr var = {beg, size, p, len}; + vars->push_back(var); + p += len; + } + + return true; +} bool DescribeAddressIfStack(uptr addr, uptr access_size) { AsanThread *t = FindThreadByStackAddress(addr); @@ -364,32 +404,19 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { alloca_stack.size = 1; Printf("%s", d.EndLocation()); alloca_stack.Print(); + + InternalMmapVector<StackVarDescr> vars(16); + if (!ParseFrameDescription(frame_descr, &vars)) { + Printf("AddressSanitizer can't parse the stack frame " + "descriptor: |%s|\n", frame_descr); + // 'addr' is a stack address, so return true even if we can't parse frame + return true; + } + uptr n_objects = vars.size(); // Report the number of stack objects. - char *p; - uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); - CHECK_GT(n_objects, 0); Printf(" This frame has %zu object(s):\n", n_objects); // Report all objects in this frame. - InternalScopedBuffer<StackVarDescr> vars(n_objects); - for (uptr i = 0; i < n_objects; i++) { - uptr beg, size; - uptr len; - beg = (uptr)internal_simple_strtoll(p, &p, 10); - size = (uptr)internal_simple_strtoll(p, &p, 10); - len = (uptr)internal_simple_strtoll(p, &p, 10); - if (beg == 0 || size == 0 || *p != ' ') { - Printf("AddressSanitizer can't parse the stack frame " - "descriptor: |%s|\n", frame_descr); - break; - } - p++; - vars[i].beg = beg; - vars[i].size = size; - vars[i].name_pos = p; - vars[i].name_len = len; - p += len; - } for (uptr i = 0; i < n_objects; i++) { buf[0] = 0; internal_strncat(buf, vars[i].name_pos, @@ -401,8 +428,12 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { prev_var_end, next_var_beg); } Printf("HINT: this may be a false positive if your program uses " - "some custom stack unwind mechanism or swapcontext\n" - " (longjmp and C++ exceptions *are* supported)\n"); + "some custom stack unwind mechanism or swapcontext\n"); + if (SANITIZER_WINDOWS) + Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); + else + Printf(" (longjmp and C++ exceptions *are* supported)\n"); + DescribeThread(t); return true; } @@ -531,7 +562,7 @@ class ScopedInErrorReport { // Do not print more than one report, otherwise they will mix up. // Error reporting functions shouldn't return at this situation, as // they are defined as no-return. - Report("AddressSanitizer: while reporting a bug found another one." + Report("AddressSanitizer: while reporting a bug found another one. " "Ignoring.\n"); u32 current_tid = GetCurrentTidOrInvalid(); if (current_tid != reporting_thread_tid) { @@ -578,8 +609,8 @@ void ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr) { Printf("%s", d.Warning()); Report( "ERROR: AddressSanitizer: stack-overflow on address %p" - " (pc %p sp %p bp %p T%d)\n", - (void *)addr, (void *)pc, (void *)sp, (void *)bp, + " (pc %p bp %p sp %p T%d)\n", + (void *)addr, (void *)pc, (void *)bp, (void *)sp, GetCurrentTidOrInvalid()); Printf("%s", d.EndWarning()); GET_STACK_TRACE_SIGNAL(pc, bp, context); @@ -587,15 +618,19 @@ void ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr) { ReportErrorSummary("stack-overflow", &stack); } -void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) { +void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp, + void *context, uptr addr) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); Report( - "ERROR: AddressSanitizer: SEGV on unknown address %p" - " (pc %p sp %p bp %p T%d)\n", - (void *)addr, (void *)pc, (void *)sp, (void *)bp, + "ERROR: AddressSanitizer: %s on unknown address %p" + " (pc %p bp %p sp %p T%d)\n", + description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, GetCurrentTidOrInvalid()); + if (pc < GetPageSizeCached()) { + Report("Hint: pc points to the zero page.\n"); + } Printf("%s", d.EndWarning()); GET_STACK_TRACE_SIGNAL(pc, bp, context); stack.Print(); @@ -621,6 +656,30 @@ void ReportDoubleFree(uptr addr, StackTrace *free_stack) { ReportErrorSummary("double-free", &stack); } +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, + StackTrace *free_stack) { + ScopedInErrorReport in_report; + Decorator d; + Printf("%s", d.Warning()); + char tname[128]; + u32 curr_tid = GetCurrentTidOrInvalid(); + Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in " + "thread T%d%s:\n", + addr, curr_tid, + ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); + Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); + Printf(" size of the allocated type: %zd bytes;\n" + " size of the deallocated type: %zd bytes.\n", + asan_mz_size(reinterpret_cast<void*>(addr)), delete_size); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + stack.Print(); + DescribeHeapAddress(addr, 1); + ReportErrorSummary("new-delete-type-mismatch", &stack); + Report("HINT: if you don't care about these warnings you may set " + "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); +} + void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; @@ -674,17 +733,17 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { ReportErrorSummary("bad-malloc_usable_size", stack); } -void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { +void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: attempting to call " - "__asan_get_allocated_size() for pointer which is " + "__sanitizer_get_allocated_size() for pointer which is " "not owned: %p\n", addr); Printf("%s", d.EndWarning()); stack->Print(); DescribeHeapAddress(addr, 1); - ReportErrorSummary("bad-__asan_get_allocated_size", stack); + ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack); } void ReportStringFunctionMemoryRangesOverlap( @@ -733,17 +792,36 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack); } -void ReportODRViolation(const __asan_global *g1, const __asan_global *g2) { +void ReportODRViolation(const __asan_global *g1, u32 stack_id1, + const __asan_global *g2, u32 stack_id2) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg); Printf("%s", d.EndWarning()); - Printf(" [1] size=%zd %s %s\n", g1->size, g1->name, g1->module_name); - Printf(" [2] size=%zd %s %s\n", g2->size, g2->name, g2->module_name); + InternalScopedString g1_loc(256), g2_loc(256); + PrintGlobalLocation(&g1_loc, *g1); + PrintGlobalLocation(&g2_loc, *g2); + Printf(" [1] size=%zd '%s' %s\n", g1->size, + MaybeDemangleGlobalName(g1->name), g1_loc.data()); + Printf(" [2] size=%zd '%s' %s\n", g2->size, + MaybeDemangleGlobalName(g2->name), g2_loc.data()); + if (stack_id1 && stack_id2) { + Printf("These globals were registered at these points:\n"); + Printf(" [1]:\n"); + uptr stack_size; + const uptr *stack_trace = StackDepotGet(stack_id1, &stack_size); + StackTrace::PrintStack(stack_trace, stack_size); + Printf(" [2]:\n"); + stack_trace = StackDepotGet(stack_id2, &stack_size); + StackTrace::PrintStack(stack_trace, stack_size); + } Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=detect_odr_violation=0\n"); - ReportErrorSummary("odr-violation", g1->module_name, 0, g1->name); + InternalScopedString error_msg(256); + error_msg.append("odr-violation: global '%s' at %s", + MaybeDemangleGlobalName(g1->name), g1_loc.data()); + ReportErrorSummary(error_msg.data()); } // ----------------------- CheckForInvalidPointerPair ----------- {{{1 @@ -831,6 +909,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, switch (*shadow_addr) { case kAsanHeapLeftRedzoneMagic: case kAsanHeapRightRedzoneMagic: + case kAsanArrayCookieMagic: bug_descr = "heap-buffer-overflow"; break; case kAsanHeapFreeMagic: @@ -867,7 +946,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, Decorator d; Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s on address " - "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n", + "%p at pc %p bp %p sp %p\n", bug_descr, (void*)addr, pc, bp, sp); Printf("%s", d.EndWarning()); @@ -899,7 +978,10 @@ void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { } void __asan_describe_address(uptr addr) { + // Thread registry must be locked while we're describing an address. + asanThreadRegistry().Lock(); DescribeAddress(addr, 1); + asanThreadRegistry().Unlock(); } extern "C" { diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index d9a0bca..4e81b9c 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -16,6 +16,13 @@ namespace __asan { +struct StackVarDescr { + uptr beg; + uptr size; + const char *name_pos; + uptr name_len; +}; + // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). void DescribeHeapAddress(uptr addr, uptr access_size); @@ -23,6 +30,8 @@ bool DescribeAddressIfGlobal(uptr addr, uptr access_size); bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, const __asan_global &g); bool DescribeAddressIfShadow(uptr addr); +bool ParseFrameDescription(const char *frame_descr, + InternalMmapVector<StackVarDescr> *vars); bool DescribeAddressIfStack(uptr addr, uptr access_size); // Determines memory type on its own. void DescribeAddress(uptr addr, uptr access_size); @@ -32,8 +41,10 @@ void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void NORETURN ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr); -void NORETURN - ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr); +void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp, + void *context, uptr addr); +void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, + StackTrace *free_stack); void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack); void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, @@ -41,8 +52,8 @@ void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType dealloc_type); void NORETURN ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack); -void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr, - StackTrace *stack); +void NORETURN +ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack); void NORETURN ReportStringFunctionMemoryRangesOverlap( const char *function, const char *offset1, uptr length1, const char *offset2, uptr length2, StackTrace *stack); @@ -53,7 +64,8 @@ ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, uptr new_mid, StackTrace *stack); void NORETURN -ReportODRViolation(const __asan_global *g1, const __asan_global *g2); +ReportODRViolation(const __asan_global *g1, u32 stack_id1, + const __asan_global *g2, u32 stack_id2); // Mac-specific errors and warnings. void WarnMacFreeUnallocated( diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 00b4b95..8fccc8d 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -171,11 +171,6 @@ static void ParseFlagsFromString(Flags *f, const char *str) { "If set, prints ASan exit stats even after program terminates " "successfully."); - ParseFlag(str, &f->disable_core, "disable_core", - "Disable core dumping. By default, disable_core=1 on 64-bit to avoid " - "dumping a 16T+ core file. " - "Ignored on OSes that don't dump core by default."); - ParseFlag(str, &f->allow_reexec, "allow_reexec", "Allow the tool to re-exec the program. This may interfere badly with " "the debugger."); @@ -189,6 +184,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) { "Poison (or not) the heap memory on [de]allocation. Zero value is useful " "for benchmarking the allocator or instrumentator."); + ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie", + "Poison (or not) the array cookie after operator new[]."); + ParseFlag(str, &f->poison_partial, "poison_partial", "If true, poison partially addressable 8-byte aligned words " "(default=true). This flag affects heap and global buffers, but not " @@ -196,6 +194,10 @@ static void ParseFlagsFromString(Flags *f, const char *str) { ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch", "Report errors on malloc/delete, new/free, new/delete[], etc."); + + ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch", + "Report errors on mismatch betwen size of new and delete."); + ParseFlag(str, &f->strict_memcmp, "strict_memcmp", "If true, assume that memcmp(p1, p2, n) always reads n bytes before " "comparing p1 and p2."); @@ -262,21 +264,23 @@ void InitializeFlags(Flags *f, const char *env) { f->print_stats = false; f->print_legend = true; f->atexit = false; - f->disable_core = (SANITIZER_WORDSIZE == 64); f->allow_reexec = true; f->print_full_thread_history = true; f->poison_heap = true; + f->poison_array_cookie = true; f->poison_partial = true; // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. // https://code.google.com/p/address-sanitizer/issues/detail?id=131 // https://code.google.com/p/address-sanitizer/issues/detail?id=309 // TODO(glider,timurrrr): Fix known issues and enable this back. f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0); + f->new_delete_type_mismatch = true; f->strict_memcmp = true; f->strict_init_order = false; f->start_deactivated = false; f->detect_invalid_pointer_pairs = 0; f->detect_container_overflow = true; + f->detect_odr_violation = 2; // Override from compile definition. ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition()); @@ -456,13 +460,6 @@ static NOINLINE void force_interface_symbols() { case 15: __asan_set_error_report_callback(0); break; case 16: __asan_handle_no_return(); break; case 17: __asan_address_is_poisoned(0); break; - case 18: __asan_get_allocated_size(0); break; - case 19: __asan_get_current_allocated_bytes(); break; - case 20: __asan_get_estimated_allocated_size(0); break; - case 21: __asan_get_free_bytes(); break; - case 22: __asan_get_heap_size(); break; - case 23: __asan_get_ownership(0); break; - case 24: __asan_get_unmapped_bytes(); break; case 25: __asan_poison_memory_region(0, 0); break; case 26: __asan_unpoison_memory_region(0, 0); break; case 27: __asan_set_error_exit_code(0); break; @@ -593,6 +590,11 @@ static void AsanInitInternal() { InitializeAsanInterceptors(); + // Enable system log ("adb logcat") on Android. + // Doing this before interceptors are initialized crashes in: + // AsanInitInternal -> android_log_write -> __interceptor_strcmp + AndroidLogInit(); + ReplaceSystemMalloc(); uptr shadow_start = kLowShadowBeg; @@ -601,7 +603,8 @@ static void AsanInitInternal() { bool full_shadow_is_available = MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); -#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING +#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ + !ASAN_FIXED_MAPPING if (!full_shadow_is_available) { kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; @@ -611,9 +614,7 @@ static void AsanInitInternal() { if (common_flags()->verbosity) PrintAddressSpaceLayout(); - if (flags()->disable_core) { - DisableCoreDumper(); - } + DisableCoreDumperIfNecessary(); if (full_shadow_is_available) { // mmap the low shadow plus at least one page at the left. @@ -648,12 +649,8 @@ static void AsanInitInternal() { AsanTSDInit(PlatformTSDDtor); InstallDeadlySignalHandlers(AsanOnSIGSEGV); - // Allocator should be initialized before starting external symbolizer, as - // fork() on Mac locks the allocator. InitializeAllocator(); - Symbolizer::Init(common_flags()->external_symbolizer_path); - // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited // should be set to 1 prior to initializing the threads. asan_inited = 1; @@ -682,7 +679,7 @@ static void AsanInitInternal() { SanitizerInitializeUnwinder(); #if CAN_SANITIZE_LEAKS - __lsan::InitCommonLsan(); + __lsan::InitCommonLsan(false); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } diff --git a/libsanitizer/asan/asan_stats.cc b/libsanitizer/asan/asan_stats.cc index 71c8582..fbd636e 100644 --- a/libsanitizer/asan/asan_stats.cc +++ b/libsanitizer/asan/asan_stats.cc @@ -13,6 +13,7 @@ #include "asan_internal.h" #include "asan_stats.h" #include "asan_thread.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -127,8 +128,8 @@ static void PrintAccumulatedStats() { BlockingMutexLock lock(&print_lock); stats.Print(); StackDepotStats *stack_depot_stats = StackDepotGetStats(); - Printf("Stats: StackDepot: %zd ids; %zdM mapped\n", - stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20); + Printf("Stats: StackDepot: %zd ids; %zdM allocated\n", + stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20); PrintInternalAllocatorStats(); } @@ -137,7 +138,7 @@ static void PrintAccumulatedStats() { // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT -uptr __asan_get_current_allocated_bytes() { +uptr __sanitizer_get_current_allocated_bytes() { AsanStats stats; GetAccumulatedStats(&stats); uptr malloced = stats.malloced; @@ -147,13 +148,13 @@ uptr __asan_get_current_allocated_bytes() { return (malloced > freed) ? malloced - freed : 1; } -uptr __asan_get_heap_size() { +uptr __sanitizer_get_heap_size() { AsanStats stats; GetAccumulatedStats(&stats); return stats.mmaped - stats.munmaped; } -uptr __asan_get_free_bytes() { +uptr __sanitizer_get_free_bytes() { AsanStats stats; GetAccumulatedStats(&stats); uptr total_free = stats.mmaped @@ -167,7 +168,7 @@ uptr __asan_get_free_bytes() { return (total_free > total_used) ? total_free - total_used : 1; } -uptr __asan_get_unmapped_bytes() { +uptr __sanitizer_get_unmapped_bytes() { return 0; } diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc index df85858..8707406 100644 --- a/libsanitizer/asan/asan_thread.cc +++ b/libsanitizer/asan/asan_thread.cc @@ -139,7 +139,10 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { } void AsanThread::Init() { + fake_stack_ = 0; // Will be initialized lazily if needed. + CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(); + CHECK_GT(this->stack_size(), 0U); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); ClearShadowForThreadStackAndTLS(); @@ -147,7 +150,6 @@ void AsanThread::Init() { VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, &local); - fake_stack_ = 0; // Will be initialized lazily if needed. AsanPlatformThreadInit(); } diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc index 03d45e38..b002876 100644 --- a/libsanitizer/asan/asan_win.cc +++ b/libsanitizer/asan/asan_win.cc @@ -19,6 +19,7 @@ #include "asan_interceptors.h" #include "asan_internal.h" +#include "asan_report.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" @@ -68,7 +69,7 @@ void *AsanDoesNotSupportStaticLinkage() { return 0; } -void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); } +void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} @@ -84,6 +85,67 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { UNIMPLEMENTED(); } +static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; + +static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { + EXCEPTION_RECORD *exception_record = info->ExceptionRecord; + CONTEXT *context = info->ContextRecord; + uptr pc = (uptr)exception_record->ExceptionAddress; +#ifdef _WIN64 + uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp; +#else + uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp; +#endif + + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || + exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { + const char *description = + (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + ? "access-violation" + : "in-page-error"; + uptr access_addr = exception_record->ExceptionInformation[1]; + ReportSIGSEGV(description, pc, sp, bp, context, access_addr); + } + + // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. + + return default_seh_handler(info); +} + +// We want to install our own exception handler (EH) to print helpful reports +// on access violations and whatnot. Unfortunately, the CRT initializers assume +// they are run before any user code and drop any previously-installed EHs on +// the floor, so we can't install our handler inside __asan_init. +// (See crt0dat.c in the CRT sources for the details) +// +// Things get even more complicated with the dynamic runtime, as it finishes its +// initialization before the .exe module CRT begins to initialize. +// +// For the static runtime (-MT), it's enough to put a callback to +// __asan_set_seh_filter in the last section for C initializers. +// +// For the dynamic runtime (-MD), we want link the same +// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter +// will be called for each instrumented module. This ensures that at least one +// __asan_set_seh_filter call happens after the .exe module CRT is initialized. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +int __asan_set_seh_filter() { + // We should only store the previous handler if it's not our own handler in + // order to avoid loops in the EH chain. + auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler); + if (prev_seh_handler != &SEHHandler) + default_seh_handler = prev_seh_handler; + return 0; +} + +#if !ASAN_DYNAMIC +// Put a pointer to __asan_set_seh_filter at the end of the global list +// of C initializers, after the default EH is set by the CRT. +#pragma section(".CRT$XIZ", long, read) // NOLINT +static __declspec(allocate(".CRT$XIZ")) + int (*__intercept_seh)() = __asan_set_seh_filter; +#endif + } // namespace __asan #endif // _WIN32 diff --git a/libsanitizer/asan/asan_dll_thunk.cc b/libsanitizer/asan/asan_win_dll_thunk.cc index 5bed39a..6adb7d2 100644 --- a/libsanitizer/asan/asan_dll_thunk.cc +++ b/libsanitizer/asan/asan_win_dll_thunk.cc @@ -1,4 +1,4 @@ -//===-- asan_dll_thunk.cc -------------------------------------------------===// +//===-- asan_win_dll_thunk.cc ---------------------------------------------===// // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. @@ -18,9 +18,10 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DLL_THUNK +#include "asan_init_version.h" #include "sanitizer_common/sanitizer_interception.h" -// ----------------- Helper functions and macros --------------------- {{{1 +// ---------- Function interception helper functions and macros ----------- {{{1 extern "C" { void *__stdcall GetModuleHandleA(const char *module_name); void *__stdcall GetProcAddress(void *module, const char *proc_name); @@ -34,68 +35,143 @@ static void *getRealProcAddressOrDie(const char *name) { return ret; } +// We need to intercept some functions (e.g. ASan interface, memory allocator -- +// let's call them "hooks") exported by the DLL thunk and forward the hooks to +// the runtime in the main module. +// However, we don't want to keep two lists of these hooks. +// To avoid that, the list of hooks should be defined using the +// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted +// at once by calling INTERCEPT_HOOKS(). + +// Use macro+template magic to automatically generate the list of hooks. +// Each hook at line LINE defines a template class with a static +// FunctionInterceptor<LINE>::Execute() method intercepting the hook. +// The default implementation of FunctionInterceptor<LINE> is to call +// the Execute() method corresponding to the previous line. +template<int LINE> +struct FunctionInterceptor { + static void Execute() { FunctionInterceptor<LINE-1>::Execute(); } +}; + +// There shouldn't be any hooks with negative definition line number. +template<> +struct FunctionInterceptor<0> { + static void Execute() {} +}; + +#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ + template<> struct FunctionInterceptor<__LINE__> { \ + static void Execute() { \ + void *wrapper = getRealProcAddressOrDie(main_function); \ + if (!__interception::OverrideFunction((uptr)dll_function, \ + (uptr)wrapper, 0)) \ + abort(); \ + FunctionInterceptor<__LINE__-1>::Execute(); \ + } \ + }; + +// Special case of hooks -- ASan own interface functions. Those are only called +// after __asan_init, thus an empty implementation is sufficient. +#define INTERFACE_FUNCTION(name) \ + extern "C" __declspec(noinline) void name() { \ + volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ + __debugbreak(); \ + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name) + +// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. +#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute + +// We can't define our own version of strlen etc. because that would lead to +// link-time or even type mismatch errors. Instead, we can declare a function +// just to be able to get its address. Me may miss the first few calls to the +// functions since it can be called before __asan_init, but that would lead to +// false negatives in the startup code before user's global initializers, which +// isn't a big deal. +#define INTERCEPT_LIBRARY_FUNCTION(name) \ + extern "C" void name(); \ + INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name) + +// Disable compiler warnings that show up if we declare our own version +// of a compiler intrinsic (e.g. strlen). +#pragma warning(disable: 4391) +#pragma warning(disable: 4392) + +static void InterceptHooks(); +// }}} + +// ---------- Function wrapping helpers ----------------------------------- {{{1 #define WRAP_V_V(name) \ extern "C" void name() { \ typedef void (*fntype)(); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_W(name) \ extern "C" void name(void *arg) { \ typedef void (*fntype)(void *arg); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WW(name) \ extern "C" void name(void *arg1, void *arg2) { \ typedef void (*fntype)(void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WWW(name) \ extern "C" void name(void *arg1, void *arg2, void *arg3) { \ typedef void *(*fntype)(void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2, arg3); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_V(name) \ extern "C" void *name() { \ typedef void *(*fntype)(); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_W(name) \ extern "C" void *name(void *arg) { \ typedef void *(*fntype)(void *arg); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WW(name) \ extern "C" void *name(void *arg1, void *arg2) { \ typedef void *(*fntype)(void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ typedef void *(*fntype)(void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ typedef void *(*fntype)(void *, void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ @@ -103,7 +179,8 @@ static void *getRealProcAddressOrDie(const char *name) { typedef void *(*fntype)(void *, void *, void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4, arg5); \ - } + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ @@ -111,48 +188,8 @@ static void *getRealProcAddressOrDie(const char *name) { typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ - } -// }}} - -// --------- Interface interception helper functions and macros ----------- {{{1 -// We need to intercept the ASan interface exported by the DLL thunk and forward -// all the functions to the runtime in the main module. -// However, we don't want to keep two lists of interface functions. -// To avoid that, the list of interface functions should be defined using the -// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once -// by calling INTERCEPT_ASAN_INTERFACE(). - -// Use macro+template magic to automatically generate the list of interface -// functions. Each interface function at line LINE defines a template class -// with a static InterfaceInteceptor<LINE>::Execute() method intercepting the -// function. The default implementation of InterfaceInteceptor<LINE> is to call -// the Execute() method corresponding to the previous line. -template<int LINE> -struct InterfaceInteceptor { - static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); } -}; - -// There shouldn't be any interface function with negative line number. -template<> -struct InterfaceInteceptor<0> { - static void Execute() {} -}; - -#define INTERFACE_FUNCTION(name) \ - extern "C" void name() { __debugbreak(); } \ - template<> struct InterfaceInteceptor<__LINE__> { \ - static void Execute() { \ - void *wrapper = getRealProcAddressOrDie(#name); \ - if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0)) \ - abort(); \ - InterfaceInteceptor<__LINE__-1>::Execute(); \ - } \ - }; - -// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION. -#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute - -static void InterceptASanInterface(); + } \ + INTERCEPT_WHEN_POSSIBLE(#name, name); // }}} // ----------------- ASan own interface functions -------------------- @@ -165,17 +202,18 @@ extern "C" { // Manually wrap __asan_init as we need to initialize // __asan_option_detect_stack_use_after_return afterwards. - void __asan_init_v3() { + void __asan_init() { typedef void (*fntype)(); static fntype fn = 0; + // __asan_init is expected to be called by only one thread. if (fn) return; - fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); + fn = (fntype)getRealProcAddressOrDie(__asan_init_name); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); - InterceptASanInterface(); + InterceptHooks(); } } @@ -195,6 +233,20 @@ INTERFACE_FUNCTION(__asan_report_load8) INTERFACE_FUNCTION(__asan_report_load16) INTERFACE_FUNCTION(__asan_report_load_n) +INTERFACE_FUNCTION(__asan_store1) +INTERFACE_FUNCTION(__asan_store2) +INTERFACE_FUNCTION(__asan_store4) +INTERFACE_FUNCTION(__asan_store8) +INTERFACE_FUNCTION(__asan_store16) +INTERFACE_FUNCTION(__asan_storeN) + +INTERFACE_FUNCTION(__asan_load1) +INTERFACE_FUNCTION(__asan_load2) +INTERFACE_FUNCTION(__asan_load4) +INTERFACE_FUNCTION(__asan_load8) +INTERFACE_FUNCTION(__asan_load16) +INTERFACE_FUNCTION(__asan_loadN) + INTERFACE_FUNCTION(__asan_memcpy); INTERFACE_FUNCTION(__asan_memset); INTERFACE_FUNCTION(__asan_memmove); @@ -211,6 +263,9 @@ INTERFACE_FUNCTION(__asan_unpoison_stack_memory) INTERFACE_FUNCTION(__asan_poison_memory_region) INTERFACE_FUNCTION(__asan_unpoison_memory_region) +INTERFACE_FUNCTION(__asan_address_is_poisoned) +INTERFACE_FUNCTION(__asan_region_is_poisoned) + INTERFACE_FUNCTION(__asan_get_current_fake_stack) INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) @@ -237,6 +292,8 @@ INTERFACE_FUNCTION(__asan_stack_free_8) INTERFACE_FUNCTION(__asan_stack_free_9) INTERFACE_FUNCTION(__asan_stack_free_10) +INTERFACE_FUNCTION(__sanitizer_cov_module_init) + // TODO(timurrrr): Add more interface functions on the as-needed basis. // ----------------- Memory allocation functions --------------------- @@ -263,8 +320,55 @@ WRAP_W_W(_expand_dbg) // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). -void InterceptASanInterface() { - INTERCEPT_ASAN_INTERFACE(); +INTERCEPT_LIBRARY_FUNCTION(atoi); +INTERCEPT_LIBRARY_FUNCTION(atol); +INTERCEPT_LIBRARY_FUNCTION(_except_handler3); + +// _except_handler4 checks -GS cookie which is different for each module, so we +// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4). +INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { + __asan_handle_no_return(); + return REAL(_except_handler4)(a, b, c, d); +} + +INTERCEPT_LIBRARY_FUNCTION(frexp); +INTERCEPT_LIBRARY_FUNCTION(longjmp); +INTERCEPT_LIBRARY_FUNCTION(memchr); +INTERCEPT_LIBRARY_FUNCTION(memcmp); +INTERCEPT_LIBRARY_FUNCTION(memcpy); +INTERCEPT_LIBRARY_FUNCTION(memmove); +INTERCEPT_LIBRARY_FUNCTION(memset); +INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT +INTERCEPT_LIBRARY_FUNCTION(strchr); +INTERCEPT_LIBRARY_FUNCTION(strcmp); +INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT +INTERCEPT_LIBRARY_FUNCTION(strlen); +INTERCEPT_LIBRARY_FUNCTION(strncat); +INTERCEPT_LIBRARY_FUNCTION(strncmp); +INTERCEPT_LIBRARY_FUNCTION(strncpy); +INTERCEPT_LIBRARY_FUNCTION(strnlen); +INTERCEPT_LIBRARY_FUNCTION(strtol); +INTERCEPT_LIBRARY_FUNCTION(wcslen); + +// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS +// is defined. +void InterceptHooks() { + INTERCEPT_HOOKS(); + INTERCEPT_FUNCTION(_except_handler4); +} + +// We want to call __asan_init before C/C++ initializers/constructors are +// executed, otherwise functions like memset might be invoked. +// For some strange reason, merely linking in asan_preinit.cc doesn't work +// as the callback is never called... Is link.exe doing something too smart? + +// In DLLs, the callbacks are expected to return 0, +// otherwise CRT initialization fails. +static int call_asan_init() { + __asan_init(); + return 0; } +#pragma section(".CRT$XIB", long, read) // NOLINT +__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; #endif // ASAN_DLL_THUNK diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc new file mode 100644 index 0000000..1b59677 --- /dev/null +++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc @@ -0,0 +1,50 @@ +//===-- asan_win_uar_thunk.cc ---------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines things that need to be present in the application modules +// to interact with the ASan DLL runtime correctly and can't be implemented +// using the default "import library" generated when linking the DLL RTL. +// +// This includes: +// - forwarding the detect_stack_use_after_return runtime option +// - installing a custom SEH handler +// +//===----------------------------------------------------------------------===// + +// Only compile this code when buidling asan_dynamic_runtime_thunk.lib +// Using #ifdef rather than relying on Makefiles etc. +// simplifies the build procedure. +#ifdef ASAN_DYNAMIC_RUNTIME_THUNK +extern "C" { +__declspec(dllimport) int __asan_set_seh_filter(); +__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); + +// Define a copy of __asan_option_detect_stack_use_after_return that should be +// used when linking an MD runtime with a set of object files on Windows. +// +// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', +// so normally we would just dllimport it. Unfortunately, the dllimport +// attribute adds __imp_ prefix to the symbol name of a variable. +// Since in general we don't know if a given TU is going to be used +// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows +// just to work around this issue, let's clone the a variable that is +// constant after initialization anyways. +int __asan_option_detect_stack_use_after_return = + __asan_should_detect_stack_use_after_return(); + +// Set the ASan-specific SEH handler at the end of CRT initialization of each +// module (see asan_win.cc for the details). +// +// Unfortunately, putting a pointer to __asan_set_seh_filter into +// __asan_intercept_seh gets optimized out, so we have to use an extra function. +static int SetSEHFilter() { return __asan_set_seh_filter(); } +#pragma section(".CRT$XIZ", long, read) // NOLINT +__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; +} +#endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/libsanitizer/asan/libtool-version b/libsanitizer/asan/libtool-version index 9a16cf5..f18f4073 100644 --- a/libsanitizer/asan/libtool-version +++ b/libsanitizer/asan/libtool-version @@ -3,4 +3,4 @@ # a separate file so that version updates don't involve re-running # automake. # CURRENT:REVISION:AGE -1:0:0 +2:0:0 |