forked from OSchip/llvm-project
[asan] Fix the deadlocks introduced by "On OS X, log reports to syslog and os_trace" commit
[asan] On OS X, log reports to syslog and os_trace, has been reverted in r252076 due to deadlocks on earlier versions of OS X. Alexey has also noticed deadlocks in some corner cases on Linux. This patch, if applied on top of the logging patch (http://reviews.llvm.org/D13452), addresses the known deadlock issues. (This also proactively removes the color escape sequences from the error report buffer since we have to copy the buffer anyway.) Differential Revision: http://reviews.llvm.org/D14470 llvm-svn: 253689
This commit is contained in:
parent
2ce9f9447c
commit
8d225205e3
|
@ -30,7 +30,6 @@ namespace __asan {
|
||||||
static void (*error_report_callback)(const char*);
|
static void (*error_report_callback)(const char*);
|
||||||
static char *error_message_buffer = nullptr;
|
static char *error_message_buffer = nullptr;
|
||||||
static uptr error_message_buffer_pos = 0;
|
static uptr error_message_buffer_pos = 0;
|
||||||
static uptr error_message_buffer_size = 0;
|
|
||||||
static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
|
static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
|
||||||
|
|
||||||
struct ReportData {
|
struct ReportData {
|
||||||
|
@ -49,17 +48,16 @@ static ReportData report_data = {};
|
||||||
void AppendToErrorMessageBuffer(const char *buffer) {
|
void AppendToErrorMessageBuffer(const char *buffer) {
|
||||||
BlockingMutexLock l(&error_message_buf_mutex);
|
BlockingMutexLock l(&error_message_buf_mutex);
|
||||||
if (!error_message_buffer) {
|
if (!error_message_buffer) {
|
||||||
error_message_buffer_size = 1 << 16;
|
|
||||||
error_message_buffer =
|
error_message_buffer =
|
||||||
(char*)MmapOrDie(error_message_buffer_size, __func__);
|
(char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
|
||||||
error_message_buffer_pos = 0;
|
error_message_buffer_pos = 0;
|
||||||
}
|
}
|
||||||
uptr length = internal_strlen(buffer);
|
uptr length = internal_strlen(buffer);
|
||||||
CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
|
RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
|
||||||
uptr remaining = error_message_buffer_size - error_message_buffer_pos;
|
uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
|
||||||
internal_strncpy(error_message_buffer + error_message_buffer_pos,
|
internal_strncpy(error_message_buffer + error_message_buffer_pos,
|
||||||
buffer, remaining);
|
buffer, remaining);
|
||||||
error_message_buffer[error_message_buffer_size - 1] = '\0';
|
error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
|
||||||
// FIXME: reallocate the buffer instead of truncating the message.
|
// FIXME: reallocate the buffer instead of truncating the message.
|
||||||
error_message_buffer_pos += Min(remaining, length);
|
error_message_buffer_pos += Min(remaining, length);
|
||||||
}
|
}
|
||||||
|
@ -686,13 +684,23 @@ class ScopedInErrorReport {
|
||||||
// Print memory stats.
|
// Print memory stats.
|
||||||
if (flags()->print_stats)
|
if (flags()->print_stats)
|
||||||
__asan_print_accumulated_stats();
|
__asan_print_accumulated_stats();
|
||||||
|
|
||||||
|
// Copy the message buffer so that we could start logging without holding a
|
||||||
|
// lock that gets aquired during printing.
|
||||||
|
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
|
||||||
{
|
{
|
||||||
BlockingMutexLock l(&error_message_buf_mutex);
|
BlockingMutexLock l(&error_message_buf_mutex);
|
||||||
LogFullErrorReport(error_message_buffer);
|
internal_memcpy(buffer_copy.data(),
|
||||||
|
error_message_buffer, kErrorMessageBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (error_report_callback) {
|
// Remove color sequences since logs cannot print them.
|
||||||
error_report_callback(error_message_buffer);
|
RemoveANSIEscapeSequencesFromString(buffer_copy.data());
|
||||||
}
|
|
||||||
|
LogFullErrorReport(buffer_copy.data());
|
||||||
|
|
||||||
|
if (error_report_callback) {
|
||||||
|
error_report_callback(buffer_copy.data());
|
||||||
}
|
}
|
||||||
CommonSanitizerReportMutex.Unlock();
|
CommonSanitizerReportMutex.Unlock();
|
||||||
reporting_thread_tid_ = kInvalidTid;
|
reporting_thread_tid_ = kInvalidTid;
|
||||||
|
|
|
@ -164,11 +164,12 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
||||||
const char *mmap_type, error_t err) {
|
const char *mmap_type, error_t err,
|
||||||
|
bool raw_report) {
|
||||||
static int recursion_count;
|
static int recursion_count;
|
||||||
if (recursion_count) {
|
if (raw_report || recursion_count) {
|
||||||
|
// If raw report is requested or we went into recursion, just die.
|
||||||
// The Report() and CHECK calls below may call mmap recursively and fail.
|
// The Report() and CHECK calls below may call mmap recursively and fail.
|
||||||
// If we went into recursion, just die.
|
|
||||||
RawWrite("ERROR: Failed to mmap\n");
|
RawWrite("ERROR: Failed to mmap\n");
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ static const uptr kMaxNumberOfModules = 1 << 14;
|
||||||
|
|
||||||
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
|
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
|
||||||
|
|
||||||
|
static const uptr kErrorMessageBufferSize = 1 << 16;
|
||||||
|
|
||||||
// Denotes fake PC values that come from JIT/JAVA/etc.
|
// Denotes fake PC values that come from JIT/JAVA/etc.
|
||||||
// For such PC values __tsan_symbolize_external() will be called.
|
// For such PC values __tsan_symbolize_external() will be called.
|
||||||
const u64 kExternalPCBit = 1ULL << 60;
|
const u64 kExternalPCBit = 1ULL << 60;
|
||||||
|
@ -76,7 +78,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||||
uptr *tls_addr, uptr *tls_size);
|
uptr *tls_addr, uptr *tls_size);
|
||||||
|
|
||||||
// Memory management
|
// Memory management
|
||||||
void *MmapOrDie(uptr size, const char *mem_type);
|
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
|
||||||
|
INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
|
||||||
|
return MmapOrDie(size, mem_type, /*raw_report*/ true);
|
||||||
|
}
|
||||||
void UnmapOrDie(void *addr, uptr size);
|
void UnmapOrDie(void *addr, uptr size);
|
||||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
|
void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
|
||||||
const char *name = nullptr);
|
const char *name = nullptr);
|
||||||
|
@ -310,7 +315,8 @@ void NORETURN Die();
|
||||||
void NORETURN
|
void NORETURN
|
||||||
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
|
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
|
||||||
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
||||||
const char *mmap_type, error_t err);
|
const char *mmap_type, error_t err,
|
||||||
|
bool raw_report = false);
|
||||||
|
|
||||||
// Set the name of the current thread to 'name', return true on succees.
|
// Set the name of the current thread to 'name', return true on succees.
|
||||||
// The name may be truncated to a system-dependent limit.
|
// The name may be truncated to a system-dependent limit.
|
||||||
|
@ -423,7 +429,7 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
|
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
|
||||||
CHECK(IsPowerOfTwo(boundary));
|
RAW_CHECK(IsPowerOfTwo(boundary));
|
||||||
return (size + boundary - 1) & ~(boundary - 1);
|
return (size + boundary - 1) & ~(boundary - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,9 +658,9 @@ enum AndroidApiLevel {
|
||||||
void WriteToSyslog(const char *buffer);
|
void WriteToSyslog(const char *buffer);
|
||||||
|
|
||||||
#if SANITIZER_MAC
|
#if SANITIZER_MAC
|
||||||
void LogFullErrorReport(const char *error_message_buffer);
|
void LogFullErrorReport(const char *buffer);
|
||||||
#else
|
#else
|
||||||
INLINE void LogFullErrorReport(const char *error_message_buffer) {}
|
INLINE void LogFullErrorReport(const char *buffer) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SANITIZER_LINUX || SANITIZER_MAC
|
#if SANITIZER_LINUX || SANITIZER_MAC
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "sanitizer_common.h"
|
#include "sanitizer_common.h"
|
||||||
#include "sanitizer_allocator_internal.h"
|
|
||||||
#include "sanitizer_flags.h"
|
#include "sanitizer_flags.h"
|
||||||
#include "sanitizer_stackdepot.h"
|
#include "sanitizer_stackdepot.h"
|
||||||
#include "sanitizer_stacktrace.h"
|
#include "sanitizer_stacktrace.h"
|
||||||
|
@ -119,13 +119,14 @@ void BackgroundThread(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteToSyslog(const char *buffer) {
|
void WriteToSyslog(const char *msg) {
|
||||||
char *copy = internal_strdup(buffer);
|
InternalScopedString msg_copy(kErrorMessageBufferSize);
|
||||||
char *p = copy;
|
msg_copy.append("%s", msg);
|
||||||
|
char *p = msg_copy.data();
|
||||||
char *q;
|
char *q;
|
||||||
|
|
||||||
// Remove color sequences since syslogs cannot print them.
|
// Remove color sequences since syslogs cannot print them.
|
||||||
RemoveANSIEscapeSequencesFromString(copy);
|
RemoveANSIEscapeSequencesFromString(p);
|
||||||
|
|
||||||
// Print one line at a time.
|
// Print one line at a time.
|
||||||
// syslog, at least on Android, has an implicit message length limit.
|
// syslog, at least on Android, has an implicit message length limit.
|
||||||
|
@ -137,7 +138,6 @@ void WriteToSyslog(const char *buffer) {
|
||||||
if (q)
|
if (q)
|
||||||
p = q + 1;
|
p = q + 1;
|
||||||
} while (q);
|
} while (q);
|
||||||
InternalFree(copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaybeStartBackgroudThread() {
|
void MaybeStartBackgroudThread() {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "sanitizer_platform.h"
|
#include "sanitizer_platform.h"
|
||||||
#if SANITIZER_MAC
|
#if SANITIZER_MAC
|
||||||
|
#include "sanitizer_mac.h"
|
||||||
|
|
||||||
// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
|
// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
|
||||||
// the clients will most certainly use 64-bit ones as well.
|
// the clients will most certainly use 64-bit ones as well.
|
||||||
|
@ -25,7 +26,6 @@
|
||||||
#include "sanitizer_flags.h"
|
#include "sanitizer_flags.h"
|
||||||
#include "sanitizer_internal_defs.h"
|
#include "sanitizer_internal_defs.h"
|
||||||
#include "sanitizer_libc.h"
|
#include "sanitizer_libc.h"
|
||||||
#include "sanitizer_mac.h"
|
|
||||||
#include "sanitizer_placement_new.h"
|
#include "sanitizer_placement_new.h"
|
||||||
#include "sanitizer_platform_limits_posix.h"
|
#include "sanitizer_platform_limits_posix.h"
|
||||||
#include "sanitizer_procmaps.h"
|
#include "sanitizer_procmaps.h"
|
||||||
|
|
|
@ -112,14 +112,14 @@ uptr GetMaxVirtualAddress() {
|
||||||
#endif // SANITIZER_WORDSIZE
|
#endif // SANITIZER_WORDSIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
|
||||||
size = RoundUpTo(size, GetPageSizeCached());
|
size = RoundUpTo(size, GetPageSizeCached());
|
||||||
uptr res = internal_mmap(nullptr, size,
|
uptr res = internal_mmap(nullptr, size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
int reserrno;
|
int reserrno;
|
||||||
if (internal_iserror(res, &reserrno))
|
if (internal_iserror(res, &reserrno))
|
||||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
|
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
|
||||||
IncreaseTotalMmap(size);
|
IncreaseTotalMmap(size);
|
||||||
return (void *)res;
|
return (void *)res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||||
}
|
}
|
||||||
#endif // #if !SANITIZER_GO
|
#endif // #if !SANITIZER_GO
|
||||||
|
|
||||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
|
||||||
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
if (rv == 0)
|
if (rv == 0)
|
||||||
ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
|
ReportMmapFailureAndDie(size, mem_type, "allocate",
|
||||||
|
GetLastError(), raw_report);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue