Index: compiler-rt/lib/asan/asan_descriptions.h =================================================================== --- compiler-rt/lib/asan/asan_descriptions.h +++ compiler-rt/lib/asan/asan_descriptions.h @@ -43,12 +43,23 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator { public: - Decorator() : SanitizerCommonDecorator() {} + Decorator() : SanitizerCommonDecorator() { + last_byte = 0; + } + const char *Reset() { + last_byte = 0; + return Default(); + } const char *Access() { return Blue(); } const char *Location() { return Green(); } const char *Allocation() { return Magenta(); } const char *ShadowByte(u8 byte) { + // Optimization: Don't return color string unless the color changes. + if (last_byte == byte) + return ""; + + last_byte = byte; switch (byte) { case kAsanHeapLeftRedzoneMagic: case kAsanArrayCookieMagic: @@ -80,8 +91,11 @@ return Default(); } } + + private: + u8 last_byte; }; enum ShadowKind : u8 { kShadowKindLow, kShadowKindGap, Index: compiler-rt/lib/asan/asan_descriptions.cc =================================================================== --- compiler-rt/lib/asan/asan_descriptions.cc +++ compiler-rt/lib/asan/asan_descriptions.cc @@ -147,13 +147,13 @@ "%p is located somewhere around (this is AddressSanitizer bug!)", (void *)descr.bad_addr); } - str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, + str.append(" %zu-byte region [%p,%p)%s\n", descr.chunk_size, (void *)descr.chunk_begin, - (void *)(descr.chunk_begin + descr.chunk_size)); - str.append("%s", d.Default()); + (void *)(descr.chunk_begin + descr.chunk_size), + d.Reset()); Printf("%s", str.data()); } bool GetHeapAddressInformation(uptr addr, uptr access_size, HeapAddressDescription *descr) { AsanChunkView chunk = FindHeapChunkByAddress(addr); @@ -422,21 +422,21 @@ if (free_tid != kInvalidTid) { free_thread = GetThreadContextByTidLocked(free_tid); Printf("%sfreed by thread %s here:%s\n", d.Allocation(), - AsanThreadIdAndName(free_thread).c_str(), d.Default()); + AsanThreadIdAndName(free_thread).c_str(), d.Reset()); StackTrace free_stack = GetStackTraceFromId(free_stack_id); free_stack.Print(); Printf("%spreviously allocated by thread %s here:%s\n", d.Allocation(), - AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); + AsanThreadIdAndName(alloc_thread).c_str(), d.Reset()); } else { Printf("%sallocated by thread %s here:%s\n", d.Allocation(), - AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); + AsanThreadIdAndName(alloc_thread).c_str(), d.Reset()); } alloc_stack.Print(); DescribeThread(GetCurrentThread()); if (free_thread) DescribeThread(free_thread); DescribeThread(alloc_thread); } AddressDescription::AddressDescription(uptr addr, uptr access_size, bool shouldLockThreadRegistry) { if (GetShadowAddressInformation(addr, &data.shadow)) { Index: compiler-rt/lib/asan/asan_errors.cc =================================================================== --- compiler-rt/lib/asan/asan_errors.cc +++ compiler-rt/lib/asan/asan_errors.cc @@ -479,70 +479,95 @@ "AddressSanitizerContainerOverflow.\n"); } -static void PrintShadowByte(InternalScopedString *str, const char *before, - u8 byte, const char *after = "\n") { - PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); +static void PrintShadowByte(InternalScopedString *str, Decorator *d, + const char *before, u8 byte, const char *after = "\n") { + PrintMemoryByte(str, d, before, byte, after); +} + +static void PrintLegendEntry(InternalScopedString *str, Decorator *d, + const char *text, u8 byte) { + PrintShadowByte(str, d, text, byte, ""); + str->append(d->Reset()); + str->append("\n"); } static void PrintLegend(InternalScopedString *str) { + Decorator d; str->append( "Shadow byte legend (one shadow byte represents %d " "application bytes):\n", (int)SHADOW_GRANULARITY); - PrintShadowByte(str, " Addressable: ", 0); + PrintShadowByte(str, &d, " Addressable: ", 0); str->append(" Partially addressable: "); - for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " "); + for (u8 i = 1; i < SHADOW_GRANULARITY; i++) + PrintShadowByte(str, &d, "", i, " "); str->append("\n"); - PrintShadowByte(str, " Heap left redzone: ", - kAsanHeapLeftRedzoneMagic); - PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic); - PrintShadowByte(str, " Stack left redzone: ", - kAsanStackLeftRedzoneMagic); - PrintShadowByte(str, " Stack mid redzone: ", - kAsanStackMidRedzoneMagic); - PrintShadowByte(str, " Stack right redzone: ", - kAsanStackRightRedzoneMagic); - PrintShadowByte(str, " Stack after return: ", - kAsanStackAfterReturnMagic); - PrintShadowByte(str, " Stack use after scope: ", - kAsanStackUseAfterScopeMagic); - PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic); - PrintShadowByte(str, " Global init order: ", - kAsanInitializationOrderMagic); - PrintShadowByte(str, " Poisoned by user: ", - kAsanUserPoisonedMemoryMagic); - PrintShadowByte(str, " Container overflow: ", - kAsanContiguousContainerOOBMagic); - PrintShadowByte(str, " Array cookie: ", - kAsanArrayCookieMagic); - PrintShadowByte(str, " Intra object redzone: ", - kAsanIntraObjectRedzone); - PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); - PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic); - PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); - PrintShadowByte(str, " Shadow gap: ", kAsanShadowGap); + PrintLegendEntry(str, &d, " Heap left redzone: ", + kAsanHeapLeftRedzoneMagic); + PrintLegendEntry(str, &d, " Freed heap region: ", + kAsanHeapFreeMagic); + PrintLegendEntry(str, &d, " Stack left redzone: ", + kAsanStackLeftRedzoneMagic); + PrintLegendEntry(str, &d, " Stack mid redzone: ", + kAsanStackMidRedzoneMagic); + PrintLegendEntry(str, &d, " Stack right redzone: ", + kAsanStackRightRedzoneMagic); + PrintLegendEntry(str, &d, " Stack after return: ", + kAsanStackAfterReturnMagic); + PrintLegendEntry(str, &d, " Stack use after scope: ", + kAsanStackUseAfterScopeMagic); + PrintLegendEntry(str, &d, " Global redzone: ", + kAsanGlobalRedzoneMagic); + PrintLegendEntry(str, &d, " Global init order: ", + kAsanInitializationOrderMagic); + PrintLegendEntry(str, &d, " Poisoned by user: ", + kAsanUserPoisonedMemoryMagic); + PrintLegendEntry(str, &d, " Container overflow: ", + kAsanContiguousContainerOOBMagic); + PrintLegendEntry(str, &d, " Array cookie: ", + kAsanArrayCookieMagic); + PrintLegendEntry(str, &d, " Intra object redzone: ", + kAsanIntraObjectRedzone); + PrintLegendEntry(str, &d, " ASan internal: ", + kAsanInternalHeapMagic); + PrintLegendEntry(str, &d, " Left alloca redzone: ", + kAsanAllocaLeftMagic); + PrintLegendEntry(str, &d, " Right alloca redzone: ", + kAsanAllocaRightMagic); + PrintLegendEntry(str, &d, " Shadow gap: ", + kAsanShadowGap); } -static void PrintShadowBytes(InternalScopedString *str, const char *before, - u8 *bytes, u8 *guilty, uptr n) { - Decorator d; +static void PrintShadowBytes(InternalScopedString *str, Decorator *d, + const char *before, u8 *bytes, u8 *guilty, uptr n) { if (before) str->append("%s%p:", before, bytes); for (uptr i = 0; i < n; i++) { u8 *p = bytes + i; - const char *before = - p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " "; - const char *after = p == guilty ? "]" : ""; - PrintShadowByte(str, before, *p, after); + const char *before; + const char *after; + if (p == guilty) { + str->append(d->Reset()); + before = "["; + PrintShadowByte(str, d, before, *p, ""); + str->append(d->Reset()); + str->append("]"); + } else { + before = (p - 1 == guilty && i != 0) ? "" : " "; + after = ""; + PrintShadowByte(str, d, before, *p, after); + } } + str->append(d->Reset()); str->append("\n"); } -static void PrintShadowMemoryForAddress(uptr addr) { +static void PrintShadowMemoryForAddress(uptr addr, Decorator *d) { if (!AddrIsInMem(addr)) return; uptr shadow_addr = MemToShadow(addr); const uptr n_bytes_per_row = 16; uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1); InternalScopedString str(4096 * 8); + str.append(d->Reset()); str.append("Shadow bytes around the buggy address:\n"); for (int i = -5; i <= 5; i++) { uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row; @@ -551,36 +576,35 @@ // space. if (!AddrIsInShadow(row_shadow_addr)) continue; const char *prefix = (i == 0) ? "=>" : " "; - PrintShadowBytes(&str, prefix, (u8 *)row_shadow_addr, (u8 *)shadow_addr, + PrintShadowBytes(&str, d, prefix, (u8 *)row_shadow_addr, (u8 *)shadow_addr, n_bytes_per_row); } if (flags()->print_legend) PrintLegend(&str); Printf("%s", str.data()); } void ErrorGeneric::Print() { Decorator d; Printf("%s", d.Error()); uptr addr = addr_description.Address(); - Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n", - bug_descr, (void *)addr, pc, bp, sp); - Printf("%s", d.Default()); + Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p%s\n", + bug_descr, (void *)addr, pc, bp, sp, d.Reset()); Printf("%s%s of size %zu at %p thread %s%s\n", d.Access(), access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size, - (void *)addr, AsanThreadIdAndName(tid).c_str(), d.Default()); + (void *)addr, AsanThreadIdAndName(tid).c_str(), d.Reset()); scariness.Print(); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); // Pass bug_descr because we have a special case for // initialization-order-fiasco addr_description.Print(bug_descr); if (shadow_val == kAsanContiguousContainerOOBMagic) PrintContainerOverflowHint(); ReportErrorSummary(bug_descr, &stack); - PrintShadowMemoryForAddress(addr); + PrintShadowMemoryForAddress(addr, &d); } } // namespace __asan Index: compiler-rt/lib/asan/asan_report.h =================================================================== --- compiler-rt/lib/asan/asan_report.h +++ compiler-rt/lib/asan/asan_report.h @@ -16,11 +16,12 @@ #define ASAN_REPORT_H #include "asan_allocator.h" +#include "asan_descriptions.h" #include "asan_internal.h" #include "asan_thread.h" namespace __asan { struct StackVarDescr { uptr beg; uptr size; @@ -38,14 +39,14 @@ void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g); void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g); -void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, - bool in_shadow, const char *after = "\n"); +void PrintMemoryByte(InternalScopedString *str, Decorator *d, + const char *before, u8 byte, const char *after); // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars); // Different kinds of error reports. void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); Index: compiler-rt/lib/asan/asan_report.cc =================================================================== --- compiler-rt/lib/asan/asan_report.cc +++ compiler-rt/lib/asan/asan_report.cc @@ -56,14 +56,12 @@ // ---------------------- Helper functions ----------------------- {{{1 -void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, - bool in_shadow, const char *after) { - Decorator d; - str->append("%s%s%x%x%s%s", before, - in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4, - byte & 15, d.Default(), after); +void PrintMemoryByte(InternalScopedString *str, Decorator *d, + const char *before, u8 byte, const char *after) { + str->append("%s%s%x%x%s", before, d->ShadowByte(byte), byte >> 4, byte & 15, + after); } static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, const char *zone_name) { if (zone_ptr) { Index: compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h +++ compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h @@ -26,11 +26,11 @@ public: SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} const char *Bold() const { return ansi_ ? "\033[1m" : ""; } - const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } + const char *Default() const { return ansi_ ? "\033[0m" : ""; } const char *Warning() const { return Red(); } const char *Error() const { return Red(); } const char *MemoryByte() const { return Magenta(); } protected: const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; }