2012-08-09 15:40:58 +08:00
|
|
|
//===-- asan_report.cc ----------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// 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 error reporting code.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2015-10-01 08:22:21 +08:00
|
|
|
|
2016-08-31 01:08:55 +08:00
|
|
|
#include "asan_errors.h"
|
2012-08-10 23:13:05 +08:00
|
|
|
#include "asan_flags.h"
|
2016-08-16 03:30:21 +08:00
|
|
|
#include "asan_descriptions.h"
|
2012-08-09 15:40:58 +08:00
|
|
|
#include "asan_internal.h"
|
2012-08-09 17:06:52 +08:00
|
|
|
#include "asan_mapping.h"
|
2012-08-09 15:40:58 +08:00
|
|
|
#include "asan_report.h"
|
2016-02-09 03:21:08 +08:00
|
|
|
#include "asan_scariness_score.h"
|
2012-08-09 15:40:58 +08:00
|
|
|
#include "asan_stack.h"
|
2012-08-09 17:27:24 +08:00
|
|
|
#include "asan_thread.h"
|
2012-12-18 15:32:16 +08:00
|
|
|
#include "sanitizer_common/sanitizer_common.h"
|
2013-05-06 19:27:58 +08:00
|
|
|
#include "sanitizer_common/sanitizer_flags.h"
|
2012-12-18 15:32:16 +08:00
|
|
|
#include "sanitizer_common/sanitizer_report_decorator.h"
|
2013-10-18 22:50:44 +08:00
|
|
|
#include "sanitizer_common/sanitizer_stackdepot.h"
|
2012-12-26 22:44:46 +08:00
|
|
|
#include "sanitizer_common/sanitizer_symbolizer.h"
|
2012-08-09 15:40:58 +08:00
|
|
|
|
|
|
|
namespace __asan {
|
|
|
|
|
2012-08-13 19:23:40 +08:00
|
|
|
// -------------------- User-specified callbacks ----------------- {{{1
|
2012-08-09 18:56:57 +08:00
|
|
|
static void (*error_report_callback)(const char*);
|
2015-10-01 08:22:21 +08:00
|
|
|
static char *error_message_buffer = nullptr;
|
2012-08-09 18:56:57 +08:00
|
|
|
static uptr error_message_buffer_pos = 0;
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
|
2015-12-10 16:08:53 +08:00
|
|
|
static const unsigned kAsanBuggyPcPoolSize = 25;
|
2015-12-10 19:07:19 +08:00
|
|
|
static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
|
2012-08-09 18:56:57 +08:00
|
|
|
|
2014-09-27 03:15:32 +08:00
|
|
|
struct ReportData {
|
|
|
|
uptr pc;
|
|
|
|
uptr sp;
|
|
|
|
uptr bp;
|
|
|
|
uptr addr;
|
|
|
|
bool is_write;
|
|
|
|
uptr access_size;
|
|
|
|
const char *description;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool report_happened = false;
|
|
|
|
static ReportData report_data = {};
|
|
|
|
|
2012-08-09 18:56:57 +08:00
|
|
|
void AppendToErrorMessageBuffer(const char *buffer) {
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
BlockingMutexLock l(&error_message_buf_mutex);
|
|
|
|
if (!error_message_buffer) {
|
|
|
|
error_message_buffer =
|
2015-11-21 02:42:01 +08:00
|
|
|
(char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
error_message_buffer_pos = 0;
|
2012-08-09 18:56:57 +08:00
|
|
|
}
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
uptr length = internal_strlen(buffer);
|
2015-11-21 02:42:01 +08:00
|
|
|
RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
|
|
|
|
uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
internal_strncpy(error_message_buffer + error_message_buffer_pos,
|
|
|
|
buffer, remaining);
|
2015-11-21 02:42:01 +08:00
|
|
|
error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
// FIXME: reallocate the buffer instead of truncating the message.
|
|
|
|
error_message_buffer_pos += Min(remaining, length);
|
2012-08-09 18:56:57 +08:00
|
|
|
}
|
|
|
|
|
2012-08-10 23:13:05 +08:00
|
|
|
// ---------------------- Helper functions ----------------------- {{{1
|
|
|
|
|
2016-09-08 20:58:15 +08:00
|
|
|
void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
|
|
|
|
bool in_shadow, const char *after) {
|
2012-12-19 17:53:32 +08:00
|
|
|
Decorator d;
|
2014-09-22 19:58:52 +08:00
|
|
|
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);
|
2012-12-19 17:53:32 +08:00
|
|
|
}
|
|
|
|
|
2014-01-23 18:52:33 +08:00
|
|
|
static void PrintShadowBytes(InternalScopedString *str, const char *before,
|
|
|
|
u8 *bytes, u8 *guilty, uptr n) {
|
2012-12-19 17:53:32 +08:00
|
|
|
Decorator d;
|
2014-01-23 18:52:33 +08:00
|
|
|
if (before) str->append("%s%p:", before, bytes);
|
2012-12-19 17:53:32 +08:00
|
|
|
for (uptr i = 0; i < n; i++) {
|
|
|
|
u8 *p = bytes + i;
|
2014-01-23 18:49:47 +08:00
|
|
|
const char *before =
|
|
|
|
p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
|
2012-12-19 17:53:32 +08:00
|
|
|
const char *after = p == guilty ? "]" : "";
|
2014-01-23 18:52:33 +08:00
|
|
|
PrintShadowByte(str, before, *p, after);
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
2014-01-23 18:52:33 +08:00
|
|
|
str->append("\n");
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
|
|
|
|
2014-01-23 18:52:33 +08:00
|
|
|
static void PrintLegend(InternalScopedString *str) {
|
|
|
|
str->append(
|
2014-01-23 18:49:47 +08:00
|
|
|
"Shadow byte legend (one shadow byte represents %d "
|
|
|
|
"application bytes):\n",
|
|
|
|
(int)SHADOW_GRANULARITY);
|
2014-01-23 18:52:33 +08:00
|
|
|
PrintShadowByte(str, " Addressable: ", 0);
|
|
|
|
str->append(" Partially addressable: ");
|
|
|
|
for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", 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);
|
2014-04-21 22:18:45 +08:00
|
|
|
PrintShadowByte(str, " Container overflow: ",
|
2013-11-19 16:40:07 +08:00
|
|
|
kAsanContiguousContainerOOBMagic);
|
2014-08-04 20:43:13 +08:00
|
|
|
PrintShadowByte(str, " Array cookie: ",
|
|
|
|
kAsanArrayCookieMagic);
|
2014-10-17 09:22:37 +08:00
|
|
|
PrintShadowByte(str, " Intra object redzone: ",
|
|
|
|
kAsanIntraObjectRedzone);
|
2014-01-23 18:52:33 +08:00
|
|
|
PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
|
2014-11-21 18:32:05 +08:00
|
|
|
PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
|
|
|
|
PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
|
|
|
|
2013-01-28 15:34:22 +08:00
|
|
|
static void PrintShadowMemoryForAddress(uptr addr) {
|
2014-01-23 18:49:47 +08:00
|
|
|
if (!AddrIsInMem(addr)) return;
|
2013-01-28 15:34:22 +08:00
|
|
|
uptr shadow_addr = MemToShadow(addr);
|
|
|
|
const uptr n_bytes_per_row = 16;
|
|
|
|
uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
|
2014-01-29 19:12:09 +08:00
|
|
|
InternalScopedString str(4096 * 8);
|
2014-01-23 18:52:33 +08:00
|
|
|
str.append("Shadow bytes around the buggy address:\n");
|
2013-01-28 15:34:22 +08:00
|
|
|
for (int i = -5; i <= 5; i++) {
|
|
|
|
const char *prefix = (i == 0) ? "=>" : " ";
|
2014-01-23 18:52:33 +08:00
|
|
|
PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
|
2014-01-23 18:49:47 +08:00
|
|
|
(u8 *)shadow_addr, n_bytes_per_row);
|
2013-01-28 15:34:22 +08:00
|
|
|
}
|
2014-01-23 18:52:33 +08:00
|
|
|
if (flags()->print_legend) PrintLegend(&str);
|
|
|
|
Printf("%s", str.data());
|
2013-01-28 15:34:22 +08:00
|
|
|
}
|
|
|
|
|
2012-08-10 23:13:05 +08:00
|
|
|
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
|
|
|
|
const char *zone_name) {
|
|
|
|
if (zone_ptr) {
|
|
|
|
if (zone_name) {
|
2012-08-28 19:34:40 +08:00
|
|
|
Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
|
2012-08-10 23:13:05 +08:00
|
|
|
ptr, zone_ptr, zone_name);
|
|
|
|
} else {
|
2012-08-28 19:34:40 +08:00
|
|
|
Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
|
2012-08-10 23:13:05 +08:00
|
|
|
ptr, zone_ptr);
|
|
|
|
}
|
|
|
|
} else {
|
2012-08-28 19:34:40 +08:00
|
|
|
Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 17:06:52 +08:00
|
|
|
// ---------------------- Address Descriptions ------------------- {{{1
|
|
|
|
|
2014-07-17 08:18:03 +08:00
|
|
|
bool ParseFrameDescription(const char *frame_descr,
|
|
|
|
InternalMmapVector<StackVarDescr> *vars) {
|
2014-10-02 05:13:00 +08:00
|
|
|
CHECK(frame_descr);
|
2014-07-17 08:18:03 +08:00
|
|
|
char *p;
|
2014-10-02 05:13:00 +08:00
|
|
|
// This string is created by the compiler and has the following form:
|
|
|
|
// "n alloc_1 alloc_2 ... alloc_n"
|
|
|
|
// where alloc_i looks like "offset size len ObjectName".
|
2014-07-17 08:18:03 +08:00
|
|
|
uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
|
2014-10-02 05:13:00 +08:00
|
|
|
if (n_objects == 0)
|
|
|
|
return false;
|
2014-07-17 08:18:03 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2013-09-03 21:58:04 +08:00
|
|
|
|
2012-08-09 17:06:52 +08:00
|
|
|
// -------------------- Different kinds of reports ----------------- {{{1
|
|
|
|
|
2012-08-10 23:13:05 +08:00
|
|
|
// Use ScopedInErrorReport to run common actions just before and
|
|
|
|
// immediately after printing error report.
|
|
|
|
class ScopedInErrorReport {
|
|
|
|
public:
|
2015-11-11 19:59:38 +08:00
|
|
|
explicit ScopedInErrorReport(ReportData *report = nullptr,
|
|
|
|
bool fatal = false) {
|
|
|
|
halt_on_error_ = fatal || flags()->halt_on_error;
|
|
|
|
|
|
|
|
if (lock_.TryLock()) {
|
|
|
|
StartReporting(report);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ASan found two bugs in different threads simultaneously.
|
|
|
|
|
|
|
|
u32 current_tid = GetCurrentTidOrInvalid();
|
2015-11-13 17:46:12 +08:00
|
|
|
if (reporting_thread_tid_ == current_tid ||
|
|
|
|
reporting_thread_tid_ == kInvalidTid) {
|
2015-11-11 19:59:38 +08:00
|
|
|
// This is either asynch signal or nested error during error reporting.
|
2015-11-13 17:46:12 +08:00
|
|
|
// Fail simple to avoid deadlocks in Report().
|
2015-11-11 19:59:38 +08:00
|
|
|
|
|
|
|
// Can't use Report() here because of potential deadlocks
|
|
|
|
// in nested signal handlers.
|
|
|
|
const char msg[] = "AddressSanitizer: nested bug in the same thread, "
|
|
|
|
"aborting.\n";
|
|
|
|
WriteToFile(kStderrFd, msg, sizeof(msg));
|
|
|
|
|
|
|
|
internal__exit(common_flags()->exitcode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (halt_on_error_) {
|
2012-08-10 23:13:05 +08:00
|
|
|
// Do not print more than one report, otherwise they will mix up.
|
|
|
|
// Error reporting functions shouldn't return at this situation, as
|
2015-11-11 19:59:38 +08:00
|
|
|
// they are effectively no-returns.
|
|
|
|
|
2014-08-27 21:43:18 +08:00
|
|
|
Report("AddressSanitizer: while reporting a bug found another one. "
|
2015-11-11 19:59:38 +08:00
|
|
|
"Ignoring.\n");
|
|
|
|
|
|
|
|
// Sleep long enough to make sure that the thread which started
|
|
|
|
// to print an error report will finish doing it.
|
|
|
|
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
|
|
|
|
2013-02-20 21:54:32 +08:00
|
|
|
// If we're still not dead for some reason, use raw _exit() instead of
|
2012-11-19 19:22:22 +08:00
|
|
|
// Die() to bypass any additional checks.
|
2015-08-22 04:49:37 +08:00
|
|
|
internal__exit(common_flags()->exitcode);
|
2015-11-11 19:59:38 +08:00
|
|
|
} else {
|
|
|
|
// The other thread will eventually finish reporting
|
|
|
|
// so it's safe to wait
|
|
|
|
lock_.Lock();
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
2015-11-11 19:59:38 +08:00
|
|
|
|
|
|
|
StartReporting(report);
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
2015-11-11 19:59:38 +08:00
|
|
|
|
|
|
|
~ScopedInErrorReport() {
|
2016-08-31 01:08:55 +08:00
|
|
|
if (current_error_.IsValid()) current_error_.Print();
|
|
|
|
|
2012-08-10 23:13:05 +08:00
|
|
|
// Make sure the current thread is announced.
|
2013-09-10 16:36:21 +08:00
|
|
|
DescribeThread(GetCurrentThread());
|
2014-05-12 16:01:51 +08:00
|
|
|
// We may want to grab this lock again when printing stats.
|
|
|
|
asanThreadRegistry().Unlock();
|
2012-08-10 23:13:05 +08:00
|
|
|
// Print memory stats.
|
2013-01-28 15:34:22 +08:00
|
|
|
if (flags()->print_stats)
|
|
|
|
__asan_print_accumulated_stats();
|
2015-11-21 02:42:01 +08:00
|
|
|
|
2016-01-18 15:55:12 +08:00
|
|
|
if (common_flags()->print_cmdline)
|
|
|
|
PrintCmdline();
|
|
|
|
|
2015-11-21 02:42:01 +08:00
|
|
|
// Copy the message buffer so that we could start logging without holding a
|
|
|
|
// lock that gets aquired during printing.
|
|
|
|
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
{
|
|
|
|
BlockingMutexLock l(&error_message_buf_mutex);
|
2015-11-21 02:42:01 +08:00
|
|
|
internal_memcpy(buffer_copy.data(),
|
|
|
|
error_message_buffer, kErrorMessageBufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
LogFullErrorReport(buffer_copy.data());
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
|
2015-11-21 02:42:01 +08:00
|
|
|
if (error_report_callback) {
|
|
|
|
error_report_callback(buffer_copy.data());
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
2015-11-11 19:59:38 +08:00
|
|
|
CommonSanitizerReportMutex.Unlock();
|
|
|
|
reporting_thread_tid_ = kInvalidTid;
|
|
|
|
lock_.Unlock();
|
|
|
|
if (halt_on_error_) {
|
|
|
|
Report("ABORTING\n");
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 01:08:55 +08:00
|
|
|
void ReportError(const ErrorDescription &description) {
|
|
|
|
// Can only report one error per ScopedInErrorReport.
|
|
|
|
CHECK_EQ(current_error_.kind, kErrorKindInvalid);
|
|
|
|
current_error_ = description;
|
|
|
|
}
|
|
|
|
|
2015-11-11 19:59:38 +08:00
|
|
|
private:
|
|
|
|
void StartReporting(ReportData *report) {
|
|
|
|
if (report) report_data = *report;
|
|
|
|
report_happened = true;
|
|
|
|
ASAN_ON_ERROR();
|
|
|
|
// Make sure the registry and sanitizer report mutexes are locked while
|
|
|
|
// we're printing an error report.
|
|
|
|
// We can lock them only here to avoid self-deadlock in case of
|
|
|
|
// recursive reports.
|
|
|
|
asanThreadRegistry().Lock();
|
|
|
|
CommonSanitizerReportMutex.Lock();
|
|
|
|
reporting_thread_tid_ = GetCurrentTidOrInvalid();
|
|
|
|
Printf("===================================================="
|
|
|
|
"=============\n");
|
2012-08-10 23:13:05 +08:00
|
|
|
}
|
2015-11-11 19:59:38 +08:00
|
|
|
|
|
|
|
static StaticSpinMutex lock_;
|
|
|
|
static u32 reporting_thread_tid_;
|
2016-08-31 01:08:55 +08:00
|
|
|
// Error currently being reported. This enables the destructor to interact
|
|
|
|
// with the debugger and point it to an error description.
|
|
|
|
static ErrorDescription current_error_;
|
2015-11-11 19:59:38 +08:00
|
|
|
bool halt_on_error_;
|
2012-08-10 23:13:05 +08:00
|
|
|
};
|
|
|
|
|
2015-11-11 19:59:38 +08:00
|
|
|
StaticSpinMutex ScopedInErrorReport::lock_;
|
2016-05-31 16:47:18 +08:00
|
|
|
u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
|
2016-08-31 01:08:55 +08:00
|
|
|
ErrorDescription ScopedInErrorReport::current_error_;
|
2015-11-11 19:59:38 +08:00
|
|
|
|
2014-11-25 21:00:21 +08:00
|
|
|
void ReportStackOverflow(const SignalContext &sig) {
|
2016-05-06 15:09:22 +08:00
|
|
|
ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
|
2016-09-13 01:10:44 +08:00
|
|
|
ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig);
|
2016-08-31 01:08:55 +08:00
|
|
|
in_report.ReportError(error);
|
2014-02-18 19:49:52 +08:00
|
|
|
}
|
|
|
|
|
2016-09-08 20:58:15 +08:00
|
|
|
void ReportDeadlySignal(int signo, const SignalContext &sig) {
|
2016-02-09 06:50:25 +08:00
|
|
|
ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
|
2016-09-13 01:10:44 +08:00
|
|
|
ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
|
2016-09-08 20:58:15 +08:00
|
|
|
in_report.ReportError(error);
|
2012-08-09 15:40:58 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2016-09-13 01:10:44 +08:00
|
|
|
ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr);
|
2016-08-31 15:38:09 +08:00
|
|
|
in_report.ReportError(error);
|
2012-08-09 16:15:46 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 22:20:54 +08:00
|
|
|
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
2014-10-26 11:35:14 +08:00
|
|
|
BufferedStackTrace *free_stack) {
|
2014-07-30 17:48:23 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2016-09-13 01:10:44 +08:00
|
|
|
ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
|
|
|
|
delete_size);
|
2016-09-07 22:20:54 +08:00
|
|
|
in_report.ReportError(error);
|
2014-07-30 17:48:23 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2016-09-14 04:47:29 +08:00
|
|
|
ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr);
|
|
|
|
in_report.ReportError(error);
|
2012-08-09 16:15:46 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
2012-12-21 16:53:59 +08:00
|
|
|
AllocType alloc_type,
|
|
|
|
AllocType dealloc_type) {
|
|
|
|
ScopedInErrorReport in_report;
|
2016-09-14 04:47:33 +08:00
|
|
|
ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
|
|
|
|
alloc_type, dealloc_type);
|
|
|
|
in_report.ReportError(error);
|
2012-12-21 16:53:59 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2016-09-14 04:47:37 +08:00
|
|
|
ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr);
|
|
|
|
in_report.ReportError(error);
|
2012-08-09 16:15:46 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
|
|
|
BufferedStackTrace *stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2012-12-18 15:32:16 +08:00
|
|
|
Decorator d;
|
|
|
|
Printf("%s", d.Warning());
|
2012-10-15 21:04:58 +08:00
|
|
|
Report("ERROR: AddressSanitizer: attempting to call "
|
2014-07-08 01:39:31 +08:00
|
|
|
"__sanitizer_get_allocated_size() for pointer which is "
|
2012-08-09 16:15:46 +08:00
|
|
|
"not owned: %p\n", addr);
|
2012-12-18 15:32:16 +08:00
|
|
|
Printf("%s", d.EndWarning());
|
2013-12-19 19:25:05 +08:00
|
|
|
stack->Print();
|
2016-08-17 17:16:08 +08:00
|
|
|
DescribeAddressIfHeap(addr);
|
2014-07-08 01:39:31 +08:00
|
|
|
ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
|
2012-08-09 16:15:46 +08:00
|
|
|
}
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
|
|
|
const char *offset1, uptr length1,
|
|
|
|
const char *offset2, uptr length2,
|
|
|
|
BufferedStackTrace *stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2012-12-18 15:32:16 +08:00
|
|
|
Decorator d;
|
2013-02-06 20:36:49 +08:00
|
|
|
char bug_type[100];
|
|
|
|
internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
|
2012-12-18 15:32:16 +08:00
|
|
|
Printf("%s", d.Warning());
|
2013-02-06 20:36:49 +08:00
|
|
|
Report("ERROR: AddressSanitizer: %s: "
|
2012-08-09 16:32:33 +08:00
|
|
|
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
2013-02-06 20:36:49 +08:00
|
|
|
bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
|
2012-12-18 15:32:16 +08:00
|
|
|
Printf("%s", d.EndWarning());
|
2016-02-09 03:21:08 +08:00
|
|
|
ScarinessScore::PrintSimple(10, bug_type);
|
2013-12-19 19:25:05 +08:00
|
|
|
stack->Print();
|
2016-08-19 21:07:23 +08:00
|
|
|
PrintAddressDescription((uptr)offset1, length1, bug_type);
|
|
|
|
PrintAddressDescription((uptr)offset2, length2, bug_type);
|
2013-11-02 01:02:14 +08:00
|
|
|
ReportErrorSummary(bug_type, stack);
|
2012-08-09 16:32:33 +08:00
|
|
|
}
|
2012-08-09 16:15:46 +08:00
|
|
|
|
2014-04-14 17:50:52 +08:00
|
|
|
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
2014-10-26 11:35:14 +08:00
|
|
|
BufferedStackTrace *stack) {
|
2014-04-14 17:50:52 +08:00
|
|
|
ScopedInErrorReport in_report;
|
|
|
|
Decorator d;
|
|
|
|
const char *bug_type = "negative-size-param";
|
|
|
|
Printf("%s", d.Warning());
|
|
|
|
Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
|
|
|
|
Printf("%s", d.EndWarning());
|
2016-02-09 03:21:08 +08:00
|
|
|
ScarinessScore::PrintSimple(10, bug_type);
|
2014-04-14 17:50:52 +08:00
|
|
|
stack->Print();
|
2016-08-19 21:07:23 +08:00
|
|
|
PrintAddressDescription(offset, size, bug_type);
|
2014-04-14 17:50:52 +08:00
|
|
|
ReportErrorSummary(bug_type, stack);
|
|
|
|
}
|
|
|
|
|
2013-12-23 15:01:43 +08:00
|
|
|
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
|
|
|
uptr old_mid, uptr new_mid,
|
2014-10-26 11:35:14 +08:00
|
|
|
BufferedStackTrace *stack) {
|
2013-12-23 15:01:43 +08:00
|
|
|
ScopedInErrorReport in_report;
|
|
|
|
Report("ERROR: AddressSanitizer: bad parameters to "
|
|
|
|
"__sanitizer_annotate_contiguous_container:\n"
|
|
|
|
" beg : %p\n"
|
|
|
|
" end : %p\n"
|
|
|
|
" old_mid : %p\n"
|
|
|
|
" new_mid : %p\n",
|
|
|
|
beg, end, old_mid, new_mid);
|
2015-02-26 01:03:34 +08:00
|
|
|
uptr granularity = SHADOW_GRANULARITY;
|
|
|
|
if (!IsAligned(beg, granularity))
|
|
|
|
Report("ERROR: beg is not aligned by %d\n", granularity);
|
2013-12-23 15:01:43 +08:00
|
|
|
stack->Print();
|
|
|
|
ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
|
|
|
|
}
|
|
|
|
|
2014-06-20 16:24:12 +08:00
|
|
|
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
|
|
|
|
const __asan_global *g2, u32 stack_id2) {
|
2014-04-25 16:58:28 +08:00
|
|
|
ScopedInErrorReport in_report;
|
|
|
|
Decorator d;
|
|
|
|
Printf("%s", d.Warning());
|
|
|
|
Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
|
|
|
|
Printf("%s", d.EndWarning());
|
2014-07-03 00:54:41 +08:00
|
|
|
InternalScopedString g1_loc(256), g2_loc(256);
|
|
|
|
PrintGlobalLocation(&g1_loc, *g1);
|
|
|
|
PrintGlobalLocation(&g2_loc, *g2);
|
2014-07-12 07:34:26 +08:00
|
|
|
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());
|
2014-06-20 16:24:12 +08:00
|
|
|
if (stack_id1 && stack_id2) {
|
|
|
|
Printf("These globals were registered at these points:\n");
|
|
|
|
Printf(" [1]:\n");
|
2014-10-26 11:35:14 +08:00
|
|
|
StackDepotGet(stack_id1).Print();
|
2014-06-20 16:24:12 +08:00
|
|
|
Printf(" [2]:\n");
|
2014-10-26 11:35:14 +08:00
|
|
|
StackDepotGet(stack_id2).Print();
|
2014-06-20 16:24:12 +08:00
|
|
|
}
|
2015-11-18 08:24:32 +08:00
|
|
|
Report("HINT: if you don't care about these errors you may set "
|
2014-04-25 16:58:28 +08:00
|
|
|
"ASAN_OPTIONS=detect_odr_violation=0\n");
|
2014-07-12 07:34:26 +08:00
|
|
|
InternalScopedString error_msg(256);
|
|
|
|
error_msg.append("odr-violation: global '%s' at %s",
|
|
|
|
MaybeDemangleGlobalName(g1->name), g1_loc.data());
|
|
|
|
ReportErrorSummary(error_msg.data());
|
2014-04-25 16:58:28 +08:00
|
|
|
}
|
|
|
|
|
2014-02-27 20:45:36 +08:00
|
|
|
// ----------------------- CheckForInvalidPointerPair ----------- {{{1
|
|
|
|
static NOINLINE void
|
|
|
|
ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
|
|
|
|
ScopedInErrorReport in_report;
|
2015-04-23 04:30:19 +08:00
|
|
|
const char *bug_type = "invalid-pointer-pair";
|
2014-02-27 20:45:36 +08:00
|
|
|
Decorator d;
|
|
|
|
Printf("%s", d.Warning());
|
|
|
|
Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
|
|
|
|
Printf("%s", d.EndWarning());
|
|
|
|
GET_STACK_TRACE_FATAL(pc, bp);
|
|
|
|
stack.Print();
|
2016-08-19 21:07:23 +08:00
|
|
|
PrintAddressDescription(a1, 1, bug_type);
|
|
|
|
PrintAddressDescription(a2, 1, bug_type);
|
2015-04-23 04:30:19 +08:00
|
|
|
ReportErrorSummary(bug_type, &stack);
|
2014-02-27 20:45:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
|
|
|
|
if (!flags()->detect_invalid_pointer_pairs) return;
|
|
|
|
uptr a1 = reinterpret_cast<uptr>(p1);
|
|
|
|
uptr a2 = reinterpret_cast<uptr>(p2);
|
|
|
|
AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
|
|
|
|
AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
|
[asan] Assert in __sanitizer_ptr_{sub,cmp} if one of the pointers was freed.
Summary:
This (partially) implements the check mentioned at
http://kristerw.blogspot.co.uk/2016/04/dangling-pointers-and-undefined-behavior.html
(via John Regehr)
Quoting:
"That the behavior is undefined follows from C11 6.2.4 "Storage
durations of objects"
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists, has
a constant address, and retains its last-stored value throughout its
lifetime. If an object is referred to outside of its lifetime, the
behavior is undefined. The value of a pointer becomes indeterminate when
the object it points to (or just past) reaches the end of its lifetime.
and 7.22.3 "Memory management functions" that says that free ends the
lifetime of objects
The lifetime of an allocated object extends from the allocation until
the deallocation.
"
We can probably implement this for stack variables too, but I think this
is a good start to see if there's interest in this check.
We can also hide this behind a flag, too.
Reviewers: samsonov, kcc, rsmith, regehr
Subscribers: kubabrecka, llvm-commits
Differential Revision: http://reviews.llvm.org/D19691
llvm-svn: 268097
2016-04-30 04:37:34 +08:00
|
|
|
bool valid1 = chunk1.IsAllocated();
|
|
|
|
bool valid2 = chunk2.IsAllocated();
|
|
|
|
if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
|
|
|
|
GET_CALLER_PC_BP_SP;
|
2014-02-27 20:45:36 +08:00
|
|
|
return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
|
|
|
|
}
|
|
|
|
}
|
2012-08-09 20:15:40 +08:00
|
|
|
// ----------------------- Mac-specific reports ----------------- {{{1
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
|
|
|
|
BufferedStackTrace *stack) {
|
2012-08-10 23:13:05 +08:00
|
|
|
ScopedInErrorReport in_report;
|
2012-08-28 19:34:40 +08:00
|
|
|
Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
2012-08-09 20:15:40 +08:00
|
|
|
"This is an unrecoverable problem, exiting now.\n",
|
|
|
|
addr);
|
|
|
|
PrintZoneForPointer(addr, zone_ptr, zone_name);
|
2013-12-19 19:25:05 +08:00
|
|
|
stack->Print();
|
2016-08-17 17:16:08 +08:00
|
|
|
DescribeAddressIfHeap(addr);
|
2012-08-09 20:15:40 +08:00
|
|
|
}
|
|
|
|
|
2015-12-10 16:08:53 +08:00
|
|
|
// -------------- SuppressErrorReport -------------- {{{1
|
|
|
|
// Avoid error reports duplicating for ASan recover mode.
|
|
|
|
static bool SuppressErrorReport(uptr pc) {
|
|
|
|
if (!common_flags()->suppress_equal_pcs) return false;
|
|
|
|
for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
|
2015-12-10 19:07:19 +08:00
|
|
|
uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
|
2015-12-10 16:08:53 +08:00
|
|
|
if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
|
|
|
|
pc, memory_order_relaxed))
|
|
|
|
return false;
|
|
|
|
if (cmp == pc) return true;
|
|
|
|
}
|
|
|
|
Die();
|
|
|
|
}
|
|
|
|
|
2016-01-21 03:49:12 +08:00
|
|
|
static void PrintContainerOverflowHint() {
|
|
|
|
Printf("HINT: if you don't care about these errors you may set "
|
|
|
|
"ASAN_OPTIONS=detect_container_overflow=0.\n"
|
|
|
|
"If you suspect a false positive see also: "
|
|
|
|
"https://github.com/google/sanitizers/wiki/"
|
|
|
|
"AddressSanitizerContainerOverflow.\n");
|
|
|
|
}
|
|
|
|
|
2016-02-10 07:46:43 +08:00
|
|
|
static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) {
|
|
|
|
return s[-1] > 127 && s[1] > 127;
|
|
|
|
}
|
|
|
|
|
2015-11-11 20:23:59 +08:00
|
|
|
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
|
|
|
uptr access_size, u32 exp, bool fatal) {
|
2015-12-10 16:08:53 +08:00
|
|
|
if (!fatal && SuppressErrorReport(pc)) return;
|
2015-01-23 07:36:47 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2016-02-09 03:21:08 +08:00
|
|
|
ScarinessScore SS;
|
|
|
|
|
|
|
|
if (access_size) {
|
|
|
|
if (access_size <= 9) {
|
|
|
|
char desr[] = "?-byte";
|
|
|
|
desr[0] = '0' + access_size;
|
|
|
|
SS.Scare(access_size + access_size / 2, desr);
|
|
|
|
} else if (access_size >= 10) {
|
|
|
|
SS.Scare(15, "multi-byte");
|
|
|
|
}
|
|
|
|
is_write ? SS.Scare(20, "write") : SS.Scare(1, "read");
|
|
|
|
}
|
2015-01-23 08:14:22 +08:00
|
|
|
|
2015-03-18 00:59:11 +08:00
|
|
|
// Optimization experiments.
|
|
|
|
// The experiments can be used to evaluate potential optimizations that remove
|
|
|
|
// instrumentation (assess false negatives). Instead of completely removing
|
|
|
|
// some instrumentation, compiler can emit special calls into runtime
|
|
|
|
// (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
|
|
|
|
// mask of experiments (exp).
|
|
|
|
// The reaction to a non-zero value of exp is to be defined.
|
|
|
|
(void)exp;
|
|
|
|
|
2012-08-10 23:13:05 +08:00
|
|
|
// Determine the error type.
|
2012-08-09 18:56:57 +08:00
|
|
|
const char *bug_descr = "unknown-crash";
|
2016-01-21 03:49:12 +08:00
|
|
|
u8 shadow_val = 0;
|
2012-08-09 18:56:57 +08:00
|
|
|
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++;
|
2016-02-09 03:21:08 +08:00
|
|
|
bool far_from_bounds = false;
|
2016-01-21 03:49:12 +08:00
|
|
|
shadow_val = *shadow_addr;
|
2016-02-09 03:21:08 +08:00
|
|
|
int bug_type_score = 0;
|
2016-03-26 08:00:19 +08:00
|
|
|
// For use-after-frees reads are almost as bad as writes.
|
|
|
|
int read_after_free_bonus = 0;
|
2016-01-21 03:49:12 +08:00
|
|
|
switch (shadow_val) {
|
2012-08-09 18:56:57 +08:00
|
|
|
case kAsanHeapLeftRedzoneMagic:
|
2014-08-04 20:43:13 +08:00
|
|
|
case kAsanArrayCookieMagic:
|
2012-08-09 18:56:57 +08:00
|
|
|
bug_descr = "heap-buffer-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 10;
|
2016-02-10 07:46:43 +08:00
|
|
|
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
|
|
|
case kAsanHeapFreeMagic:
|
|
|
|
bug_descr = "heap-use-after-free";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 20;
|
2016-03-26 08:00:19 +08:00
|
|
|
if (!is_write) read_after_free_bonus = 18;
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
|
|
|
case kAsanStackLeftRedzoneMagic:
|
|
|
|
bug_descr = "stack-buffer-underflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 25;
|
2016-02-10 07:46:43 +08:00
|
|
|
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
2012-08-21 22:10:25 +08:00
|
|
|
case kAsanInitializationOrderMagic:
|
|
|
|
bug_descr = "initialization-order-fiasco";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 1;
|
2012-08-21 22:10:25 +08:00
|
|
|
break;
|
2012-08-09 18:56:57 +08:00
|
|
|
case kAsanStackMidRedzoneMagic:
|
|
|
|
case kAsanStackRightRedzoneMagic:
|
|
|
|
bug_descr = "stack-buffer-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 25;
|
2016-02-10 07:46:43 +08:00
|
|
|
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
|
|
|
case kAsanStackAfterReturnMagic:
|
|
|
|
bug_descr = "stack-use-after-return";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 30;
|
2016-03-26 08:00:19 +08:00
|
|
|
if (!is_write) read_after_free_bonus = 18;
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
|
|
|
case kAsanUserPoisonedMemoryMagic:
|
|
|
|
bug_descr = "use-after-poison";
|
2016-02-10 07:46:43 +08:00
|
|
|
bug_type_score = 20;
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
2013-11-19 16:40:07 +08:00
|
|
|
case kAsanContiguousContainerOOBMagic:
|
2013-11-21 20:23:52 +08:00
|
|
|
bug_descr = "container-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 10;
|
2013-11-19 16:40:07 +08:00
|
|
|
break;
|
2012-12-04 09:38:15 +08:00
|
|
|
case kAsanStackUseAfterScopeMagic:
|
|
|
|
bug_descr = "stack-use-after-scope";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 10;
|
2012-12-04 09:38:15 +08:00
|
|
|
break;
|
2012-08-09 18:56:57 +08:00
|
|
|
case kAsanGlobalRedzoneMagic:
|
|
|
|
bug_descr = "global-buffer-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 10;
|
2016-02-10 07:46:43 +08:00
|
|
|
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
2012-08-09 18:56:57 +08:00
|
|
|
break;
|
2014-10-17 09:22:37 +08:00
|
|
|
case kAsanIntraObjectRedzone:
|
|
|
|
bug_descr = "intra-object-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 10;
|
2014-10-17 09:22:37 +08:00
|
|
|
break;
|
2014-11-21 18:32:05 +08:00
|
|
|
case kAsanAllocaLeftMagic:
|
|
|
|
case kAsanAllocaRightMagic:
|
|
|
|
bug_descr = "dynamic-stack-buffer-overflow";
|
2016-02-09 03:21:08 +08:00
|
|
|
bug_type_score = 25;
|
2016-02-10 07:46:43 +08:00
|
|
|
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
2014-11-21 18:32:05 +08:00
|
|
|
break;
|
2012-08-09 18:56:57 +08:00
|
|
|
}
|
2016-03-26 08:00:19 +08:00
|
|
|
SS.Scare(bug_type_score + read_after_free_bonus, bug_descr);
|
2016-02-09 03:21:08 +08:00
|
|
|
if (far_from_bounds)
|
|
|
|
SS.Scare(10, "far-from-bounds");
|
2012-08-09 18:56:57 +08:00
|
|
|
}
|
2014-09-27 03:15:32 +08:00
|
|
|
|
|
|
|
ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
|
|
|
|
bug_descr };
|
2015-11-11 19:59:38 +08:00
|
|
|
ScopedInErrorReport in_report(&report, fatal);
|
2014-09-27 03:15:32 +08:00
|
|
|
|
2012-12-18 15:32:16 +08:00
|
|
|
Decorator d;
|
|
|
|
Printf("%s", d.Warning());
|
2012-10-15 21:04:58 +08:00
|
|
|
Report("ERROR: AddressSanitizer: %s on address "
|
2014-07-11 20:14:46 +08:00
|
|
|
"%p at pc %p bp %p sp %p\n",
|
2012-08-09 18:56:57 +08:00
|
|
|
bug_descr, (void*)addr, pc, bp, sp);
|
2012-12-18 15:32:16 +08:00
|
|
|
Printf("%s", d.EndWarning());
|
2012-08-09 18:56:57 +08:00
|
|
|
|
2013-03-20 17:23:28 +08:00
|
|
|
u32 curr_tid = GetCurrentTidOrInvalid();
|
2012-12-07 23:15:01 +08:00
|
|
|
char tname[128];
|
2012-12-18 15:32:16 +08:00
|
|
|
Printf("%s%s of size %zu at %p thread T%d%s%s\n",
|
|
|
|
d.Access(),
|
|
|
|
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
|
|
|
|
access_size, (void*)addr, curr_tid,
|
|
|
|
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
|
|
|
|
d.EndAccess());
|
2012-08-09 18:56:57 +08:00
|
|
|
|
2016-02-09 03:21:08 +08:00
|
|
|
SS.Print();
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_FATAL(pc, bp);
|
2013-12-19 19:25:05 +08:00
|
|
|
stack.Print();
|
2012-08-09 18:56:57 +08:00
|
|
|
|
2016-08-19 21:07:23 +08:00
|
|
|
PrintAddressDescription(addr, access_size, bug_descr);
|
2016-01-21 03:49:12 +08:00
|
|
|
if (shadow_val == kAsanContiguousContainerOOBMagic)
|
|
|
|
PrintContainerOverflowHint();
|
2013-11-02 01:02:14 +08:00
|
|
|
ReportErrorSummary(bug_descr, &stack);
|
2012-08-10 23:13:05 +08:00
|
|
|
PrintShadowMemoryForAddress(addr);
|
2012-08-09 18:56:57 +08:00
|
|
|
}
|
|
|
|
|
2015-11-11 19:59:38 +08:00
|
|
|
} // namespace __asan
|
|
|
|
|
|
|
|
// --------------------------- Interface --------------------- {{{1
|
|
|
|
using namespace __asan; // NOLINT
|
|
|
|
|
|
|
|
void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
|
|
|
|
uptr access_size, u32 exp) {
|
|
|
|
ENABLE_FRAME_POINTER;
|
|
|
|
bool fatal = flags()->halt_on_error;
|
|
|
|
ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
|
|
|
|
}
|
|
|
|
|
2012-08-09 18:56:57 +08:00
|
|
|
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
|
Reapply: [asan] On OS X, log reports to syslog and os_trace
When ASan currently detects a bug, by default it will only print out the text
of the report to stderr. This patch changes this behavior and writes the full
text of the report to syslog before we terminate the process. It also calls
os_trace (Activity Tracing available on OS X and iOS) with a message saying
that the report is available in syslog. This is useful, because this message
will be shown in the crash log.
For this to work, the patch makes sure we store the full report into
error_message_buffer unconditionally, and it also strips out ANSI escape
sequences from the report (they are used when producing colored reports).
I've initially tried to log to syslog during printing, which is done on Android
right now. The advantage is that if we crash during error reporting or the
produced error does not go through ScopedInErrorReport, we would still get a
(partial) message in the syslog. However, that solution is very problematic on
OS X. One issue is that the logging routine uses GCD, which may spawn a new
thread on its behalf. In many cases, the reporting logic locks threadRegistry,
which leads to deadlocks.
Reviewed at http://reviews.llvm.org/D13452
(In addition, add sanitizer_common_libcdep.cc to buildgo.sh to avoid
build failures on Linux.)
llvm-svn: 253688
2015-11-21 02:41:44 +08:00
|
|
|
BlockingMutexLock l(&error_message_buf_mutex);
|
2012-08-09 18:56:57 +08:00
|
|
|
error_report_callback = callback;
|
|
|
|
}
|
2012-08-13 19:23:40 +08:00
|
|
|
|
2012-12-29 18:18:31 +08:00
|
|
|
void __asan_describe_address(uptr addr) {
|
2014-07-22 05:33:46 +08:00
|
|
|
// Thread registry must be locked while we're describing an address.
|
|
|
|
asanThreadRegistry().Lock();
|
2016-08-19 21:07:23 +08:00
|
|
|
PrintAddressDescription(addr, 1, "");
|
2014-07-22 05:33:46 +08:00
|
|
|
asanThreadRegistry().Unlock();
|
2012-12-29 18:18:31 +08:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:15:32 +08:00
|
|
|
int __asan_report_present() {
|
|
|
|
return report_happened ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr __asan_get_report_pc() {
|
|
|
|
return report_data.pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr __asan_get_report_bp() {
|
|
|
|
return report_data.bp;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr __asan_get_report_sp() {
|
|
|
|
return report_data.sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr __asan_get_report_address() {
|
|
|
|
return report_data.addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __asan_get_report_access_type() {
|
|
|
|
return report_data.is_write ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptr __asan_get_report_access_size() {
|
|
|
|
return report_data.access_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *__asan_get_report_description() {
|
|
|
|
return report_data.description;
|
|
|
|
}
|
|
|
|
|
2014-02-27 20:45:36 +08:00
|
|
|
extern "C" {
|
|
|
|
SANITIZER_INTERFACE_ATTRIBUTE
|
|
|
|
void __sanitizer_ptr_sub(void *a, void *b) {
|
|
|
|
CheckForInvalidPointerPair(a, b);
|
|
|
|
}
|
|
|
|
SANITIZER_INTERFACE_ATTRIBUTE
|
|
|
|
void __sanitizer_ptr_cmp(void *a, void *b) {
|
|
|
|
CheckForInvalidPointerPair(a, b);
|
|
|
|
}
|
2015-10-01 08:22:21 +08:00
|
|
|
} // extern "C"
|
2014-02-27 20:45:36 +08:00
|
|
|
|
2012-12-08 06:01:28 +08:00
|
|
|
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
2012-10-02 22:06:39 +08:00
|
|
|
// Provide default implementation of __asan_on_error that does nothing
|
|
|
|
// and may be overriden by user.
|
2013-08-13 19:42:45 +08:00
|
|
|
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
|
2012-10-02 22:06:39 +08:00
|
|
|
void __asan_on_error() {}
|
2012-12-08 06:01:28 +08:00
|
|
|
#endif
|