namespace __asan {
+// ---------------------- Error report callback ------------------- {{{1
+static void (*error_report_callback)(const char*);
+static char *error_message_buffer = 0;
+static uptr error_message_buffer_pos = 0;
+static uptr error_message_buffer_size = 0;
+
+void AppendToErrorMessageBuffer(const char *buffer) {
+ if (error_message_buffer) {
+ uptr length = internal_strlen(buffer);
+ CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
+ uptr remaining = error_message_buffer_size - error_message_buffer_pos;
+ internal_strncpy(error_message_buffer + error_message_buffer_pos,
+ buffer, remaining);
+ error_message_buffer[error_message_buffer_size - 1] = '\0';
+ // FIXME: reallocate the buffer instead of truncating the message.
+ error_message_buffer_pos += remaining > length ? length : remaining;
+ }
+}
+
// ---------------------- Address Descriptions ------------------- {{{1
static bool IsASCII(unsigned char c) {
ShowStatsAndAbort();
}
+static void PrintBytes(const char *before, uptr *a) {
+ u8 *bytes = (u8*)a;
+ uptr byte_num = (__WORDSIZE) / 8;
+ AsanPrintf("%s%p:", before, (void*)a);
+ for (uptr i = 0; i < byte_num; i++) {
+ AsanPrintf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
+ }
+ AsanPrintf("\n");
+}
+
+void ReportInvalidMemoryAccess(uptr pc, uptr bp, uptr sp, uptr addr,
+ bool is_write, uptr access_size) {
+ static atomic_uint32_t num_calls;
+ if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+ // Do not print more than one report, otherwise they will mix up.
+ // We can not return here because the function is marked as never-return.
+ AsanPrintf("AddressSanitizer: while reporting a bug found another one."
+ "Ignoring.\n");
+ SleepForSeconds(5);
+ Die();
+ }
+
+ AsanPrintf("===================================================="
+ "=============\n");
+ const char *bug_descr = "unknown-crash";
+ if (AddrIsInMem(addr)) {
+ u8 *shadow_addr = (u8*)MemToShadow(addr);
+ // If we are accessing 16 bytes, look at the second shadow byte.
+ if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
+ shadow_addr++;
+ // If we are in the partial right redzone, look at the next shadow byte.
+ if (*shadow_addr > 0 && *shadow_addr < 128)
+ shadow_addr++;
+ switch (*shadow_addr) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanHeapRightRedzoneMagic:
+ bug_descr = "heap-buffer-overflow";
+ break;
+ case kAsanHeapFreeMagic:
+ bug_descr = "heap-use-after-free";
+ break;
+ case kAsanStackLeftRedzoneMagic:
+ bug_descr = "stack-buffer-underflow";
+ break;
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ case kAsanStackPartialRedzoneMagic:
+ bug_descr = "stack-buffer-overflow";
+ break;
+ case kAsanStackAfterReturnMagic:
+ bug_descr = "stack-use-after-return";
+ break;
+ case kAsanUserPoisonedMemoryMagic:
+ bug_descr = "use-after-poison";
+ break;
+ case kAsanGlobalRedzoneMagic:
+ bug_descr = "global-buffer-overflow";
+ break;
+ }
+ }
+
+ AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+ u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
+
+ if (curr_thread) {
+ // We started reporting an error message. Stop using the fake stack
+ // in case we will call an instrumented function from a symbolizer.
+ curr_thread->fake_stack().StopUsingFakeStack();
+ }
+
+ AsanReport("ERROR: AddressSanitizer %s on address "
+ "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
+ bug_descr, (void*)addr, pc, bp, sp);
+
+ AsanPrintf("%s of size %zu at %p thread T%d\n",
+ access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
+ access_size, (void*)addr, curr_tid);
+
+ if (flags()->debug) {
+ PrintBytes("PC: ", (uptr*)pc);
+ }
+
+ GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
+ stack.PrintStack();
+
+ DescribeAddress(addr, access_size);
+
+ if (AddrIsInMem(addr)) {
+ uptr shadow_addr = MemToShadow(addr);
+ AsanReport("ABORTING\n");
+ __asan_print_accumulated_stats();
+ AsanPrintf("Shadow byte and word:\n");
+ AsanPrintf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
+ uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
+ PrintBytes(" ", (uptr*)(aligned_shadow));
+ AsanPrintf("More shadow bytes:\n");
+ PrintBytes(" ", (uptr*)(aligned_shadow-4*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow-3*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow-2*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow-1*kWordSize));
+ PrintBytes("=>", (uptr*)(aligned_shadow+0*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow+1*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow+2*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow+3*kWordSize));
+ PrintBytes(" ", (uptr*)(aligned_shadow+4*kWordSize));
+ }
+ if (error_report_callback) {
+ error_report_callback(error_message_buffer);
+ }
+ Die();
+}
+
} // namespace __asan
+
+// --------------------------- Interface --------------------- {{{1
+using namespace __asan; // NOLINT
+
+void __asan_report_error(uptr pc, uptr bp, uptr sp,
+ uptr addr, bool is_write, uptr access_size) {
+ ReportInvalidMemoryAccess(pc, bp, sp, addr, is_write, access_size);
+}
+
+void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
+ error_report_callback = callback;
+ if (callback) {
+ error_message_buffer_size = 1 << 16;
+ error_message_buffer =
+ (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
+ error_message_buffer_pos = 0;
+ }
+}
void NORETURN ReportStringFunctionMemoryRangesOverlap(
const char *function, const char *offset1, uptr length1,
const char *offset2, uptr length2, AsanStackTrace *stack);
+// Generic error report.
+void NORETURN ReportInvalidMemoryAccess(uptr pc, uptr bp, uptr sp, uptr addr,
+ bool is_write, uptr access_size);
} // namespace __asan
int asan_inited;
bool asan_init_is_running;
void (*death_callback)(void);
-static void (*error_report_callback)(const char*);
-char *error_message_buffer = 0;
-uptr error_message_buffer_pos = 0;
-uptr error_message_buffer_size = 0;
// -------------------------- Misc ---------------- {{{1
void ShowStatsAndAbort() {
Die();
}
-static void PrintBytes(const char *before, uptr *a) {
- u8 *bytes = (u8*)a;
- uptr byte_num = (__WORDSIZE) / 8;
- AsanPrintf("%s%p:", before, (void*)a);
- for (uptr i = 0; i < byte_num; i++) {
- AsanPrintf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
- }
- AsanPrintf("\n");
-}
-
-void AppendToErrorMessageBuffer(const char *buffer) {
- if (error_message_buffer) {
- uptr length = internal_strlen(buffer);
- CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
- uptr remaining = error_message_buffer_size - error_message_buffer_pos;
- internal_strncpy(error_message_buffer + error_message_buffer_pos,
- buffer, remaining);
- error_message_buffer[error_message_buffer_size - 1] = '\0';
- // FIXME: reallocate the buffer instead of truncating the message.
- error_message_buffer_pos += remaining > length ? length : remaining;
- }
-}
-
// ---------------------- mmap -------------------- {{{1
// Reserve memory range [beg, end].
static void ReserveShadowMemoryRange(uptr beg, uptr end) {
}
}
-// -------------------------- Init ------------------- {{{1
static void asan_atexit() {
AsanPrintf("AddressSanitizer exit stats:\n");
__asan_print_accumulated_stats();
death_callback = callback;
}
-void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
- error_report_callback = callback;
- if (callback) {
- error_message_buffer_size = 1 << 16;
- error_message_buffer =
- (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
- error_message_buffer_pos = 0;
- }
-}
-
-void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size) {
- static atomic_uint32_t num_calls;
- if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
- // Do not print more than one report, otherwise they will mix up.
- // We can not return here because the function is marked as never-return.
- AsanPrintf("AddressSanitizer: while reporting a bug found another one."
- "Ignoring.\n");
- SleepForSeconds(5);
- Die();
- }
-
- AsanPrintf("===================================================="
- "=============\n");
- const char *bug_descr = "unknown-crash";
- if (AddrIsInMem(addr)) {
- u8 *shadow_addr = (u8*)MemToShadow(addr);
- // If we are accessing 16 bytes, look at the second shadow byte.
- if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
- shadow_addr++;
- // If we are in the partial right redzone, look at the next shadow byte.
- if (*shadow_addr > 0 && *shadow_addr < 128)
- shadow_addr++;
- switch (*shadow_addr) {
- case kAsanHeapLeftRedzoneMagic:
- case kAsanHeapRightRedzoneMagic:
- bug_descr = "heap-buffer-overflow";
- break;
- case kAsanHeapFreeMagic:
- bug_descr = "heap-use-after-free";
- break;
- case kAsanStackLeftRedzoneMagic:
- bug_descr = "stack-buffer-underflow";
- break;
- case kAsanStackMidRedzoneMagic:
- case kAsanStackRightRedzoneMagic:
- case kAsanStackPartialRedzoneMagic:
- bug_descr = "stack-buffer-overflow";
- break;
- case kAsanStackAfterReturnMagic:
- bug_descr = "stack-use-after-return";
- break;
- case kAsanUserPoisonedMemoryMagic:
- bug_descr = "use-after-poison";
- break;
- case kAsanGlobalRedzoneMagic:
- bug_descr = "global-buffer-overflow";
- break;
- }
- }
-
- AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
- u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
-
- if (curr_thread) {
- // We started reporting an error message. Stop using the fake stack
- // in case we will call an instrumented function from a symbolizer.
- curr_thread->fake_stack().StopUsingFakeStack();
- }
-
- AsanReport("ERROR: AddressSanitizer %s on address "
- "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
- bug_descr, (void*)addr, pc, bp, sp);
-
- AsanPrintf("%s of size %zu at %p thread T%d\n",
- access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
- access_size, (void*)addr, curr_tid);
-
- if (flags()->debug) {
- PrintBytes("PC: ", (uptr*)pc);
- }
-
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
- stack.PrintStack();
-
- DescribeAddress(addr, access_size);
-
- if (AddrIsInMem(addr)) {
- uptr shadow_addr = MemToShadow(addr);
- AsanReport("ABORTING\n");
- __asan_print_accumulated_stats();
- AsanPrintf("Shadow byte and word:\n");
- AsanPrintf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
- uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
- PrintBytes(" ", (uptr*)(aligned_shadow));
- AsanPrintf("More shadow bytes:\n");
- PrintBytes(" ", (uptr*)(aligned_shadow-4*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow-3*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow-2*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow-1*kWordSize));
- PrintBytes("=>", (uptr*)(aligned_shadow+0*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow+1*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow+2*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow+3*kWordSize));
- PrintBytes(" ", (uptr*)(aligned_shadow+4*kWordSize));
- }
- if (error_report_callback) {
- error_report_callback(error_message_buffer);
- }
- Die();
-}
-
-
void __asan_init() {
if (asan_inited) return;
asan_init_is_running = true;