Index: lib/asan/asan_flags.h =================================================================== --- lib/asan/asan_flags.h +++ lib/asan/asan_flags.h @@ -65,6 +65,7 @@ int detect_invalid_pointer_pairs; bool detect_container_overflow; int detect_odr_violation; + bool dump_instruction_bytes; }; extern Flags asan_flags_dont_use_directly; Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -86,15 +86,24 @@ } } const char *EndShadowByte() { return Default(); } + const char *MemoryByte() { return Magenta(); } + const char *EndMemoryByte() { return Default(); } }; // ---------------------- Helper functions ----------------------- {{{1 -static void PrintShadowByte(InternalScopedString *str, const char *before, - u8 byte, const char *after = "\n") { +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte, bool in_shadow, const char *after = "\n") { Decorator d; - str->append("%s%s%x%x%s%s", before, d.ShadowByte(byte), byte >> 4, byte & 15, - d.EndShadowByte(), after); + str->append("%s%s%x%x%s%s", before, + in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), + byte >> 4, byte & 15, + in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after); +} + +static void PrintShadowByte(InternalScopedString *str, const char *before, + u8 byte, const char *after = "\n") { + PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); } static void PrintShadowBytes(InternalScopedString *str, const char *before, @@ -149,6 +158,20 @@ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); } +void MaybeDumpInstructionBytes(uptr pc) { + if (!flags()->dump_instruction_bytes) + return; + InternalScopedString str(1024); + if (pc >= GetPageSizeCached()) { + str.append("First 16 instruction bytes at pc: "); + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((char *)pc)[i], /*in_shadow*/false, " "); + } + str.append("\n"); + Report("%s", str.data()); + } +} + static void PrintShadowMemoryForAddress(uptr addr) { if (!AddrIsInMem(addr)) return; uptr shadow_addr = MemToShadow(addr); @@ -630,9 +653,13 @@ " (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(); + MaybeDumpInstructionBytes(pc); Printf("AddressSanitizer can not provide additional info.\n"); ReportErrorSummary("SEGV", &stack); } Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -230,6 +230,9 @@ "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " "have different sizes"); + + ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes", + "If true, dump 16 bytes starting at the instruction that caused SEGV"); } void InitializeFlags(Flags *f, const char *env) { Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -148,7 +148,9 @@ struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)handler; - sigact.sa_flags = SA_SIGINFO; + // Do not block the signal from being received in that signal's handler. + // Clients are responsible for handling this correctly. + sigact.sa_flags = SA_SIGINFO | SA_NODEFER; if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, internal_sigaction(signum, &sigact, 0)); VReport(1, "Installed the sigaction for signal %d\n", signum); Index: test/asan/TestCases/dump_instruction_bytes.cc =================================================================== --- test/asan/TestCases/dump_instruction_bytes.cc +++ test/asan/TestCases/dump_instruction_bytes.cc @@ -0,0 +1,22 @@ +// Check that ASan prints the faulting instruction bytes on +// dump_instruction_bytes=1 +// RUN: %clangxx_asan %s -o %t +// RUN: env ASAN_OPTIONS=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP + +int main() { +#if defined(__x86_64__) + asm("movq $0, %rax"); + asm("movl $0xcafebabe, 0x0(%rax)"); +#elif defined(i386) + asm("movl $0, %eax"); + asm("movl $0xcafebabe, 0x0(%eax)"); +#elif defined(__arm__) + asm("mov %r0, $0xcafebabe"); + asm("mov %r1, $0x0"); + asm("str %r0, [%r1]"); +#endif + // CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca + // CHECK-NODUMP-NOT: First 16 instruction bytes + return 0; +} Index: test/asan/TestCases/zero_page_pc.cc =================================================================== --- test/asan/TestCases/zero_page_pc.cc +++ test/asan/TestCases/zero_page_pc.cc @@ -0,0 +1,11 @@ +// Check that ASan correctly detects SEGV on the zero page. +// RUN: %clangxx_asan %s -o %t && not %run %t 2>&1 | FileCheck %s + +typedef void void_f(); +int main() { + void_f *func = (void_f *)0x7; + func(); + // CHECK: {{AddressSanitizer: SEGV.*(pc.*0007)}} + // CHECK: Hint: pc points to the zero page. + return 0; +}