[Sanitizer]: Introduce a common internal printf function. For now, also use tool-specific wrappers TsanPrintf (its output is controlled by TSan flags) and AsanPrintf (which copies its results to the ASan-private buffer). Supported formats: %[z]{d,u,x}, %s, %p. Re-write all format strings in TSan according to this format (this should have no effect on 64-bit platforms).
llvm-svn: 158065
This commit is contained in:
parent
88aeaf6ac4
commit
51ae983718
|
@ -217,18 +217,18 @@ struct AsanChunk: public ChunkBase {
|
||||||
|
|
||||||
void DescribeAddress(uptr addr, uptr access_size) {
|
void DescribeAddress(uptr addr, uptr access_size) {
|
||||||
uptr offset;
|
uptr offset;
|
||||||
Printf("%p is located ", (void*)addr);
|
AsanPrintf("%p is located ", (void*)addr);
|
||||||
if (AddrIsInside(addr, access_size, &offset)) {
|
if (AddrIsInside(addr, access_size, &offset)) {
|
||||||
Printf("%zu bytes inside of", offset);
|
AsanPrintf("%zu bytes inside of", offset);
|
||||||
} else if (AddrIsAtLeft(addr, access_size, &offset)) {
|
} else if (AddrIsAtLeft(addr, access_size, &offset)) {
|
||||||
Printf("%zu bytes to the left of", offset);
|
AsanPrintf("%zu bytes to the left of", offset);
|
||||||
} else if (AddrIsAtRight(addr, access_size, &offset)) {
|
} else if (AddrIsAtRight(addr, access_size, &offset)) {
|
||||||
Printf("%zu bytes to the right of", offset);
|
AsanPrintf("%zu bytes to the right of", offset);
|
||||||
} else {
|
} else {
|
||||||
Printf(" somewhere around (this is AddressSanitizer bug!)");
|
AsanPrintf(" somewhere around (this is AddressSanitizer bug!)");
|
||||||
}
|
}
|
||||||
Printf(" %zu-byte region [%p,%p)\n",
|
AsanPrintf(" %zu-byte region [%p,%p)\n",
|
||||||
used_size, (void*)beg(), (void*)(beg() + used_size));
|
used_size, (void*)beg(), (void*)(beg() + used_size));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -588,20 +588,20 @@ static void Describe(uptr addr, uptr access_size) {
|
||||||
if (m->free_tid >= 0) {
|
if (m->free_tid >= 0) {
|
||||||
AsanThreadSummary *free_thread =
|
AsanThreadSummary *free_thread =
|
||||||
asanThreadRegistry().FindByTid(m->free_tid);
|
asanThreadRegistry().FindByTid(m->free_tid);
|
||||||
Printf("freed by thread T%d here:\n", free_thread->tid());
|
AsanPrintf("freed by thread T%d here:\n", free_thread->tid());
|
||||||
AsanStackTrace free_stack;
|
AsanStackTrace free_stack;
|
||||||
AsanStackTrace::UncompressStack(&free_stack, m->compressed_free_stack(),
|
AsanStackTrace::UncompressStack(&free_stack, m->compressed_free_stack(),
|
||||||
m->compressed_free_stack_size());
|
m->compressed_free_stack_size());
|
||||||
free_stack.PrintStack();
|
free_stack.PrintStack();
|
||||||
Printf("previously allocated by thread T%d here:\n",
|
AsanPrintf("previously allocated by thread T%d here:\n",
|
||||||
alloc_thread->tid());
|
alloc_thread->tid());
|
||||||
|
|
||||||
alloc_stack.PrintStack();
|
alloc_stack.PrintStack();
|
||||||
t->summary()->Announce();
|
t->summary()->Announce();
|
||||||
free_thread->Announce();
|
free_thread->Announce();
|
||||||
alloc_thread->Announce();
|
alloc_thread->Announce();
|
||||||
} else {
|
} else {
|
||||||
Printf("allocated by thread T%d here:\n", alloc_thread->tid());
|
AsanPrintf("allocated by thread T%d here:\n", alloc_thread->tid());
|
||||||
alloc_stack.PrintStack();
|
alloc_stack.PrintStack();
|
||||||
t->summary()->Announce();
|
t->summary()->Announce();
|
||||||
alloc_thread->Announce();
|
alloc_thread->Announce();
|
||||||
|
@ -711,13 +711,13 @@ static void Deallocate(u8 *ptr, AsanStackTrace *stack) {
|
||||||
u16 old_chunk_state = AtomicExchange(&m->chunk_state, CHUNK_QUARANTINE);
|
u16 old_chunk_state = AtomicExchange(&m->chunk_state, CHUNK_QUARANTINE);
|
||||||
|
|
||||||
if (old_chunk_state == CHUNK_QUARANTINE) {
|
if (old_chunk_state == CHUNK_QUARANTINE) {
|
||||||
Report("ERROR: AddressSanitizer attempting double-free on %p:\n", ptr);
|
AsanReport("ERROR: AddressSanitizer attempting double-free on %p:\n", ptr);
|
||||||
stack->PrintStack();
|
stack->PrintStack();
|
||||||
Describe((uptr)ptr, 1);
|
Describe((uptr)ptr, 1);
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
} else if (old_chunk_state != CHUNK_ALLOCATED) {
|
} else if (old_chunk_state != CHUNK_ALLOCATED) {
|
||||||
Report("ERROR: AddressSanitizer attempting free on address which was not"
|
AsanReport("ERROR: AddressSanitizer attempting free on address "
|
||||||
" malloc()-ed: %p\n", ptr);
|
"which was not malloc()-ed: %p\n", ptr);
|
||||||
stack->PrintStack();
|
stack->PrintStack();
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
}
|
}
|
||||||
|
@ -867,8 +867,9 @@ uptr asan_malloc_usable_size(void *ptr, AsanStackTrace *stack) {
|
||||||
if (ptr == 0) return 0;
|
if (ptr == 0) return 0;
|
||||||
uptr usable_size = malloc_info.AllocationSize((uptr)ptr);
|
uptr usable_size = malloc_info.AllocationSize((uptr)ptr);
|
||||||
if (FLAG_check_malloc_usable_size && (usable_size == 0)) {
|
if (FLAG_check_malloc_usable_size && (usable_size == 0)) {
|
||||||
Report("ERROR: AddressSanitizer attempting to call malloc_usable_size() "
|
AsanReport("ERROR: AddressSanitizer attempting to call "
|
||||||
"for pointer which is not owned: %p\n", ptr);
|
"malloc_usable_size() for pointer which is "
|
||||||
|
"not owned: %p\n", ptr);
|
||||||
stack->PrintStack();
|
stack->PrintStack();
|
||||||
Describe((uptr)ptr, 1);
|
Describe((uptr)ptr, 1);
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
|
@ -1072,9 +1073,9 @@ uptr __asan_get_allocated_size(const void *p) {
|
||||||
uptr allocated_size = malloc_info.AllocationSize((uptr)p);
|
uptr allocated_size = malloc_info.AllocationSize((uptr)p);
|
||||||
// Die if p is not malloced or if it is already freed.
|
// Die if p is not malloced or if it is already freed.
|
||||||
if (allocated_size == 0) {
|
if (allocated_size == 0) {
|
||||||
Report("ERROR: AddressSanitizer attempting to call "
|
AsanReport("ERROR: AddressSanitizer attempting to call "
|
||||||
"__asan_get_allocated_size() for pointer which is "
|
"__asan_get_allocated_size() for pointer which is "
|
||||||
"not owned: %p\n", p);
|
"not owned: %p\n", p);
|
||||||
PRINT_CURRENT_STACK();
|
PRINT_CURRENT_STACK();
|
||||||
Describe((uptr)p, 1);
|
Describe((uptr)p, 1);
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
|
|
|
@ -66,22 +66,22 @@ void PrintIfASCII(const Global &g) {
|
||||||
if (!isascii(*(char*)p)) return;
|
if (!isascii(*(char*)p)) return;
|
||||||
}
|
}
|
||||||
if (*(char*)(g.beg + g.size - 1) != 0) return;
|
if (*(char*)(g.beg + g.size - 1) != 0) return;
|
||||||
Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
|
AsanPrintf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DescribeAddrIfMyRedZone(const Global &g, uptr addr) {
|
bool DescribeAddrIfMyRedZone(const Global &g, uptr addr) {
|
||||||
if (addr < g.beg - kGlobalAndStackRedzone) return false;
|
if (addr < g.beg - kGlobalAndStackRedzone) return false;
|
||||||
if (addr >= g.beg + g.size_with_redzone) return false;
|
if (addr >= g.beg + g.size_with_redzone) return false;
|
||||||
Printf("%p is located ", (void*)addr);
|
AsanPrintf("%p is located ", (void*)addr);
|
||||||
if (addr < g.beg) {
|
if (addr < g.beg) {
|
||||||
Printf("%zd bytes to the left", g.beg - addr);
|
AsanPrintf("%zd bytes to the left", g.beg - addr);
|
||||||
} else if (addr >= g.beg + g.size) {
|
} else if (addr >= g.beg + g.size) {
|
||||||
Printf("%zd bytes to the right", addr - (g.beg + g.size));
|
AsanPrintf("%zd bytes to the right", addr - (g.beg + g.size));
|
||||||
} else {
|
} else {
|
||||||
Printf("%zd bytes inside", addr - g.beg); // Can it happen?
|
AsanPrintf("%zd bytes inside", addr - g.beg); // Can it happen?
|
||||||
}
|
}
|
||||||
Printf(" of global variable '%s' (0x%zx) of size %zu\n",
|
AsanPrintf(" of global variable '%s' (0x%zx) of size %zu\n",
|
||||||
g.name, g.beg, g.size);
|
g.name, g.beg, g.size);
|
||||||
PrintIfASCII(g);
|
PrintIfASCII(g);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,8 @@ bool DescribeAddrIfGlobal(uptr addr) {
|
||||||
for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
|
for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
|
||||||
const Global &g = *l->g;
|
const Global &g = *l->g;
|
||||||
if (FLAG_report_globals >= 2)
|
if (FLAG_report_globals >= 2)
|
||||||
Printf("Search Global: beg=%p size=%zu name=%s\n",
|
AsanPrintf("Search Global: beg=%p size=%zu name=%s\n",
|
||||||
(void*)g.beg, g.size, (char*)g.name);
|
(void*)g.beg, g.size, (char*)g.name);
|
||||||
res |= DescribeAddrIfMyRedZone(g, addr);
|
res |= DescribeAddrIfMyRedZone(g, addr);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -155,9 +155,9 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||||
const char *offset1 = (const char*)_offset1; \
|
const char *offset1 = (const char*)_offset1; \
|
||||||
const char *offset2 = (const char*)_offset2; \
|
const char *offset2 = (const char*)_offset2; \
|
||||||
if (RangesOverlap(offset1, length1, offset2, length2)) { \
|
if (RangesOverlap(offset1, length1, offset2, length2)) { \
|
||||||
Report("ERROR: AddressSanitizer %s-param-overlap: " \
|
AsanReport("ERROR: AddressSanitizer %s-param-overlap: " \
|
||||||
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
||||||
name, offset1, offset1 + length1, offset2, offset2 + length2); \
|
name, offset1, offset1 + length1, offset2, offset2 + length2); \
|
||||||
PRINT_CURRENT_STACK(); \
|
PRINT_CURRENT_STACK(); \
|
||||||
ShowStatsAndAbort(); \
|
ShowStatsAndAbort(); \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -157,11 +157,10 @@ void AsanTSDSet(void *tsd);
|
||||||
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||||
uptr *buff_size, uptr max_len);
|
uptr *buff_size, uptr max_len);
|
||||||
|
|
||||||
|
void AppendToErrorMessageBuffer(const char *buffer);
|
||||||
// asan_printf.cc
|
// asan_printf.cc
|
||||||
void RawWrite(const char *buffer);
|
void AsanPrintf(const char *format, ...) FORMAT(1, 2);
|
||||||
int SNPrintf(char *buffer, uptr length, const char *format, ...);
|
void AsanReport(const char *format, ...) FORMAT(1, 2);
|
||||||
void Printf(const char *format, ...);
|
|
||||||
void Report(const char *format, ...);
|
|
||||||
|
|
||||||
// Don't use std::min and std::max, to minimize dependency on libstdc++.
|
// Don't use std::min and std::max, to minimize dependency on libstdc++.
|
||||||
template<class T> T Min(T a, T b) { return a < b ? a : b; }
|
template<class T> T Min(T a, T b) { return a < b ? a : b; }
|
||||||
|
|
|
@ -119,14 +119,14 @@ void print_zone_for_ptr(void *ptr) {
|
||||||
malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
|
malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
|
||||||
if (orig_zone) {
|
if (orig_zone) {
|
||||||
if (orig_zone->zone_name) {
|
if (orig_zone->zone_name) {
|
||||||
Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
|
AsanPrintf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
|
||||||
ptr, orig_zone, orig_zone->zone_name);
|
ptr, orig_zone, orig_zone->zone_name);
|
||||||
} else {
|
} else {
|
||||||
Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
|
AsanPrintf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
|
||||||
ptr, orig_zone);
|
ptr, orig_zone);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
|
AsanPrintf("malloc_zone_from_ptr(%p) = 0\n", ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,8 +146,9 @@ void mz_free(malloc_zone_t *zone, void *ptr) {
|
||||||
asan_free(ptr, &stack);
|
asan_free(ptr, &stack);
|
||||||
} else {
|
} else {
|
||||||
// Let us just leak this memory for now.
|
// Let us just leak this memory for now.
|
||||||
Printf("mz_free(%p) -- attempting to free unallocated memory.\n"
|
AsanPrintf("mz_free(%p) -- attempting to free unallocated memory.\n"
|
||||||
"AddressSanitizer is ignoring this error on Mac OS now.\n", ptr);
|
"AddressSanitizer is ignoring this error on Mac OS now.\n",
|
||||||
|
ptr);
|
||||||
print_zone_for_ptr(ptr);
|
print_zone_for_ptr(ptr);
|
||||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||||
stack.PrintStack();
|
stack.PrintStack();
|
||||||
|
@ -170,8 +171,9 @@ void cf_free(void *ptr, void *info) {
|
||||||
asan_free(ptr, &stack);
|
asan_free(ptr, &stack);
|
||||||
} else {
|
} else {
|
||||||
// Let us just leak this memory for now.
|
// Let us just leak this memory for now.
|
||||||
Printf("cf_free(%p) -- attempting to free unallocated memory.\n"
|
AsanPrintf("cf_free(%p) -- attempting to free unallocated memory.\n"
|
||||||
"AddressSanitizer is ignoring this error on Mac OS now.\n", ptr);
|
"AddressSanitizer is ignoring this error on Mac OS now.\n",
|
||||||
|
ptr);
|
||||||
print_zone_for_ptr(ptr);
|
print_zone_for_ptr(ptr);
|
||||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||||
stack.PrintStack();
|
stack.PrintStack();
|
||||||
|
@ -191,8 +193,9 @@ void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
|
||||||
// We can't recover from reallocating an unknown address, because
|
// We can't recover from reallocating an unknown address, because
|
||||||
// this would require reading at most |size| bytes from
|
// this would require reading at most |size| bytes from
|
||||||
// potentially unaccessible memory.
|
// potentially unaccessible memory.
|
||||||
Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
AsanPrintf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
||||||
"This is an unrecoverable problem, exiting now.\n", ptr);
|
"This is an unrecoverable problem, exiting now.\n",
|
||||||
|
ptr);
|
||||||
print_zone_for_ptr(ptr);
|
print_zone_for_ptr(ptr);
|
||||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||||
stack.PrintStack();
|
stack.PrintStack();
|
||||||
|
@ -214,8 +217,9 @@ void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
|
||||||
// We can't recover from reallocating an unknown address, because
|
// We can't recover from reallocating an unknown address, because
|
||||||
// this would require reading at most |size| bytes from
|
// this would require reading at most |size| bytes from
|
||||||
// potentially unaccessible memory.
|
// potentially unaccessible memory.
|
||||||
Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
AsanPrintf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
||||||
"This is an unrecoverable problem, exiting now.\n", ptr);
|
"This is an unrecoverable problem, exiting now.\n",
|
||||||
|
ptr);
|
||||||
print_zone_for_ptr(ptr);
|
print_zone_for_ptr(ptr);
|
||||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||||
stack.PrintStack();
|
stack.PrintStack();
|
||||||
|
@ -227,7 +231,7 @@ void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
|
||||||
|
|
||||||
void mz_destroy(malloc_zone_t* zone) {
|
void mz_destroy(malloc_zone_t* zone) {
|
||||||
// A no-op -- we will not be destroyed!
|
// A no-op -- we will not be destroyed!
|
||||||
Printf("mz_destroy() called -- ignoring\n");
|
AsanPrintf("mz_destroy() called -- ignoring\n");
|
||||||
}
|
}
|
||||||
// from AvailabilityMacros.h
|
// from AvailabilityMacros.h
|
||||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||||
|
|
|
@ -86,11 +86,11 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
|
||||||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||||
uptr pc, sp, bp;
|
uptr pc, sp, bp;
|
||||||
GetPcSpBp(context, &pc, &sp, &bp);
|
GetPcSpBp(context, &pc, &sp, &bp);
|
||||||
Report("ERROR: AddressSanitizer crashed on unknown address %p"
|
AsanReport("ERROR: AddressSanitizer crashed on unknown address %p"
|
||||||
" (pc %p sp %p bp %p T%d)\n",
|
" (pc %p sp %p bp %p T%d)\n",
|
||||||
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
|
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
|
||||||
asanThreadRegistry().GetCurrentTidOrMinusOne());
|
asanThreadRegistry().GetCurrentTidOrMinusOne());
|
||||||
Printf("AddressSanitizer can not provide additional info. ABORTING\n");
|
AsanPrintf("AddressSanitizer can not provide additional info. ABORTING\n");
|
||||||
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
|
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
|
||||||
stack.PrintStack();
|
stack.PrintStack();
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
|
|
|
@ -17,143 +17,18 @@
|
||||||
#include "asan_internal.h"
|
#include "asan_internal.h"
|
||||||
#include "asan_interceptors.h"
|
#include "asan_interceptors.h"
|
||||||
#include "sanitizer_common/sanitizer_libc.h"
|
#include "sanitizer_common/sanitizer_libc.h"
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __sanitizer {
|
||||||
|
int VSNPrintf(char *buff, int buff_length, const char *format, va_list args);
|
||||||
|
} // namespace __sanitizer
|
||||||
|
|
||||||
namespace __asan {
|
namespace __asan {
|
||||||
|
|
||||||
extern char *error_message_buffer;
|
void AsanPrintf(const char *format, ...) {
|
||||||
extern uptr error_message_buffer_pos, error_message_buffer_size;
|
|
||||||
|
|
||||||
void RawWrite(const char *buffer) {
|
|
||||||
static const char *kRawWriteError = "RawWrite can't output requested buffer!";
|
|
||||||
uptr length = (uptr)internal_strlen(buffer);
|
|
||||||
if (length != internal_write(2, buffer, length)) {
|
|
||||||
internal_write(2, kRawWriteError, internal_strlen(kRawWriteError));
|
|
||||||
Die();
|
|
||||||
}
|
|
||||||
if (error_message_buffer) {
|
|
||||||
int 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int AppendChar(char **buff, const char *buff_end, char c) {
|
|
||||||
if (*buff < buff_end) {
|
|
||||||
**buff = c;
|
|
||||||
(*buff)++;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appends number in a given base to buffer. If its length is less than
|
|
||||||
// "minimal_num_length", it is padded with leading zeroes.
|
|
||||||
static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
|
||||||
u8 base, u8 minimal_num_length) {
|
|
||||||
uptr const kMaxLen = 30;
|
|
||||||
RAW_CHECK(base == 10 || base == 16);
|
|
||||||
RAW_CHECK(minimal_num_length < kMaxLen);
|
|
||||||
uptr num_buffer[kMaxLen];
|
|
||||||
uptr pos = 0;
|
|
||||||
do {
|
|
||||||
RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
|
|
||||||
num_buffer[pos++] = num % base;
|
|
||||||
num /= base;
|
|
||||||
} while (num > 0);
|
|
||||||
while (pos < minimal_num_length) num_buffer[pos++] = 0;
|
|
||||||
int result = 0;
|
|
||||||
while (pos-- > 0) {
|
|
||||||
uptr digit = num_buffer[pos];
|
|
||||||
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
|
|
||||||
: 'a' + digit - 10);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int AppendSignedDecimal(char **buff, const char *buff_end,
|
|
||||||
s64 num) {
|
|
||||||
int result = 0;
|
|
||||||
if (num < 0) {
|
|
||||||
result += AppendChar(buff, buff_end, '-');
|
|
||||||
num = -num;
|
|
||||||
}
|
|
||||||
result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int AppendString(char **buff, const char *buff_end,
|
|
||||||
const char *s) {
|
|
||||||
// Avoid library functions like stpcpy here.
|
|
||||||
RAW_CHECK_MSG(s, "Error: passing a 0 pointer to AppendString\n");
|
|
||||||
int result = 0;
|
|
||||||
for (; *s; s++) {
|
|
||||||
result += AppendChar(buff, buff_end, *s);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int AppendPointer(char **buff, const char *buff_end,
|
|
||||||
u64 ptr_value) {
|
|
||||||
int result = 0;
|
|
||||||
result += AppendString(buff, buff_end, "0x");
|
|
||||||
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
|
|
||||||
(__WORDSIZE == 64) ? 12 : 8);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int VSNPrintf(char *buff, int buff_length,
|
|
||||||
const char *format, va_list args) {
|
|
||||||
static const char *kPrintfFormatsHelp = "Supported Printf formats: "
|
|
||||||
"%%[z]{d,u,x}; %%p; %%s";
|
|
||||||
RAW_CHECK(format);
|
|
||||||
RAW_CHECK(buff_length > 0);
|
|
||||||
const char *buff_end = &buff[buff_length - 1];
|
|
||||||
const char *cur = format;
|
|
||||||
int result = 0;
|
|
||||||
for (; *cur; cur++) {
|
|
||||||
if (*cur == '%') {
|
|
||||||
cur++;
|
|
||||||
bool have_z = (*cur == 'z');
|
|
||||||
cur += have_z;
|
|
||||||
s64 dval;
|
|
||||||
u64 uval;
|
|
||||||
switch (*cur) {
|
|
||||||
case 'd': dval = have_z ? va_arg(args, sptr)
|
|
||||||
: va_arg(args, int);
|
|
||||||
result += AppendSignedDecimal(&buff, buff_end, dval);
|
|
||||||
break;
|
|
||||||
case 'u': uval = have_z ? va_arg(args, uptr)
|
|
||||||
: va_arg(args, unsigned);
|
|
||||||
result += AppendUnsigned(&buff, buff_end, uval, 10, 0);
|
|
||||||
break;
|
|
||||||
case 'x': uval = have_z ? va_arg(args, uptr)
|
|
||||||
: va_arg(args, unsigned);
|
|
||||||
result += AppendUnsigned(&buff, buff_end, uval, 16, 0);
|
|
||||||
break;
|
|
||||||
case 'p': RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
|
||||||
result += AppendPointer(&buff, buff_end,
|
|
||||||
va_arg(args, uptr));
|
|
||||||
break;
|
|
||||||
case 's': RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
|
||||||
result += AppendString(&buff, buff_end, va_arg(args, char*));
|
|
||||||
break;
|
|
||||||
default: RAW_CHECK_MSG(false, kPrintfFormatsHelp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result += AppendChar(&buff, buff_end, *cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RAW_CHECK(buff <= buff_end);
|
|
||||||
AppendChar(&buff, buff_end + 1, '\0');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Printf(const char *format, ...) {
|
|
||||||
const int kLen = 1024 * 4;
|
const int kLen = 1024 * 4;
|
||||||
char buffer[kLen];
|
char buffer[kLen];
|
||||||
va_list args;
|
va_list args;
|
||||||
|
@ -162,22 +37,11 @@ void Printf(const char *format, ...) {
|
||||||
va_end(args);
|
va_end(args);
|
||||||
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
|
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
|
||||||
RawWrite(buffer);
|
RawWrite(buffer);
|
||||||
|
AppendToErrorMessageBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes at most "length" symbols to "buffer" (including trailing '\0').
|
// Like AsanPrintf, but prints the current PID before the output string.
|
||||||
// Returns the number of symbols that should have been written to buffer
|
void AsanReport(const char *format, ...) {
|
||||||
// (not including trailing '\0'). Thus, the string is truncated
|
|
||||||
// iff return value is not less than "length".
|
|
||||||
int SNPrintf(char *buffer, uptr length, const char *format, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
int needed_length = VSNPrintf(buffer, length, format, args);
|
|
||||||
va_end(args);
|
|
||||||
return needed_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like Printf, but prints the current PID before the output string.
|
|
||||||
void Report(const char *format, ...) {
|
|
||||||
const int kLen = 1024 * 4;
|
const int kLen = 1024 * 4;
|
||||||
char buffer[kLen];
|
char buffer[kLen];
|
||||||
int needed_length = SNPrintf(buffer, kLen, "==%d== ", GetPid());
|
int needed_length = SNPrintf(buffer, kLen, "==%d== ", GetPid());
|
||||||
|
@ -189,6 +53,7 @@ void Report(const char *format, ...) {
|
||||||
va_end(args);
|
va_end(args);
|
||||||
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
||||||
RawWrite(buffer);
|
RawWrite(buffer);
|
||||||
|
AppendToErrorMessageBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace __asan
|
} // namespace __asan
|
||||||
|
|
|
@ -95,11 +95,11 @@ void ShowStatsAndAbort() {
|
||||||
static void PrintBytes(const char *before, uptr *a) {
|
static void PrintBytes(const char *before, uptr *a) {
|
||||||
u8 *bytes = (u8*)a;
|
u8 *bytes = (u8*)a;
|
||||||
uptr byte_num = (__WORDSIZE) / 8;
|
uptr byte_num = (__WORDSIZE) / 8;
|
||||||
Printf("%s%p:", before, (void*)a);
|
AsanPrintf("%s%p:", before, (void*)a);
|
||||||
for (uptr i = 0; i < byte_num; i++) {
|
for (uptr i = 0; i < byte_num; i++) {
|
||||||
Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
|
AsanPrintf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
|
||||||
}
|
}
|
||||||
Printf("\n");
|
AsanPrintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||||
|
@ -133,11 +133,23 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||||
return read_len;
|
return read_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendToErrorMessageBuffer(const char *buffer) {
|
||||||
|
if (error_message_buffer) {
|
||||||
|
uptr length = (uptr)internal_strlen(buffer);
|
||||||
|
int 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
|
// ---------------------- mmap -------------------- {{{1
|
||||||
void OutOfMemoryMessageAndDie(const char *mem_type, uptr size) {
|
void OutOfMemoryMessageAndDie(const char *mem_type, uptr size) {
|
||||||
Report("ERROR: AddressSanitizer failed to allocate "
|
AsanReport("ERROR: AddressSanitizer failed to allocate "
|
||||||
"0x%zx (%zd) bytes of %s\n",
|
"0x%zx (%zd) bytes of %s\n",
|
||||||
size, size, mem_type);
|
size, size, mem_type);
|
||||||
PRINT_CURRENT_STACK();
|
PRINT_CURRENT_STACK();
|
||||||
ShowStatsAndAbort();
|
ShowStatsAndAbort();
|
||||||
}
|
}
|
||||||
|
@ -187,14 +199,14 @@ static bool DescribeStackAddress(uptr addr, uptr access_size) {
|
||||||
internal_strncat(buf, frame_descr,
|
internal_strncat(buf, frame_descr,
|
||||||
Min(kBufSize,
|
Min(kBufSize,
|
||||||
static_cast<sptr>(name_end - frame_descr)));
|
static_cast<sptr>(name_end - frame_descr)));
|
||||||
Printf("Address %p is located at offset %zu "
|
AsanPrintf("Address %p is located at offset %zu "
|
||||||
"in frame <%s> of T%d's stack:\n",
|
"in frame <%s> of T%d's stack:\n",
|
||||||
(void*)addr, offset, buf, t->tid());
|
(void*)addr, offset, buf, t->tid());
|
||||||
// Report the number of stack objects.
|
// Report the number of stack objects.
|
||||||
char *p;
|
char *p;
|
||||||
uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
|
uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
|
||||||
CHECK(n_objects > 0);
|
CHECK(n_objects > 0);
|
||||||
Printf(" This frame has %zu object(s):\n", n_objects);
|
AsanPrintf(" This frame has %zu object(s):\n", n_objects);
|
||||||
// Report all objects in this frame.
|
// Report all objects in this frame.
|
||||||
for (uptr i = 0; i < n_objects; i++) {
|
for (uptr i = 0; i < n_objects; i++) {
|
||||||
uptr beg, size;
|
uptr beg, size;
|
||||||
|
@ -203,19 +215,19 @@ static bool DescribeStackAddress(uptr addr, uptr access_size) {
|
||||||
size = internal_simple_strtoll(p, &p, 10);
|
size = internal_simple_strtoll(p, &p, 10);
|
||||||
len = internal_simple_strtoll(p, &p, 10);
|
len = internal_simple_strtoll(p, &p, 10);
|
||||||
if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
|
if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
|
||||||
Printf("AddressSanitizer can't parse the stack frame descriptor: |%s|\n",
|
AsanPrintf("AddressSanitizer can't parse the stack frame "
|
||||||
frame_descr);
|
"descriptor: |%s|\n", frame_descr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
internal_strncat(buf, p, Min(kBufSize, len));
|
internal_strncat(buf, p, Min(kBufSize, len));
|
||||||
p += len;
|
p += len;
|
||||||
Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
|
AsanPrintf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
|
||||||
}
|
}
|
||||||
Printf("HINT: this may be a false positive if your program uses "
|
AsanPrintf("HINT: this may be a false positive if your program uses "
|
||||||
"some custom stack unwind mechanism\n"
|
"some custom stack unwind mechanism\n"
|
||||||
" (longjmp and C++ exceptions *are* supported)\n");
|
" (longjmp and C++ exceptions *are* supported)\n");
|
||||||
t->summary()->Announce();
|
t->summary()->Announce();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +332,7 @@ static void BoolFlagValue(const char *flags, const char *flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asan_atexit() {
|
static void asan_atexit() {
|
||||||
Printf("AddressSanitizer exit stats:\n");
|
AsanPrintf("AddressSanitizer exit stats:\n");
|
||||||
__asan_print_accumulated_stats();
|
__asan_print_accumulated_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +382,8 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||||
static int num_calls = 0;
|
static int num_calls = 0;
|
||||||
if (AtomicInc(&num_calls) > 1) return;
|
if (AtomicInc(&num_calls) > 1) return;
|
||||||
|
|
||||||
Printf("=================================================================\n");
|
AsanPrintf("===================================================="
|
||||||
|
"=============\n");
|
||||||
const char *bug_descr = "unknown-crash";
|
const char *bug_descr = "unknown-crash";
|
||||||
if (AddrIsInMem(addr)) {
|
if (AddrIsInMem(addr)) {
|
||||||
u8 *shadow_addr = (u8*)MemToShadow(addr);
|
u8 *shadow_addr = (u8*)MemToShadow(addr);
|
||||||
|
@ -417,13 +430,13 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||||
curr_thread->fake_stack().StopUsingFakeStack();
|
curr_thread->fake_stack().StopUsingFakeStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
Report("ERROR: AddressSanitizer %s on address "
|
AsanReport("ERROR: AddressSanitizer %s on address "
|
||||||
"%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
|
"%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
|
||||||
bug_descr, (void*)addr, pc, bp, sp);
|
bug_descr, (void*)addr, pc, bp, sp);
|
||||||
|
|
||||||
Printf("%s of size %zu at %p thread T%d\n",
|
AsanPrintf("%s of size %zu at %p thread T%d\n",
|
||||||
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
|
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
|
||||||
access_size, (void*)addr, curr_tid);
|
access_size, (void*)addr, curr_tid);
|
||||||
|
|
||||||
if (FLAG_debug) {
|
if (FLAG_debug) {
|
||||||
PrintBytes("PC: ", (uptr*)pc);
|
PrintBytes("PC: ", (uptr*)pc);
|
||||||
|
@ -437,13 +450,13 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||||
DescribeAddress(addr, access_size);
|
DescribeAddress(addr, access_size);
|
||||||
|
|
||||||
uptr shadow_addr = MemToShadow(addr);
|
uptr shadow_addr = MemToShadow(addr);
|
||||||
Report("ABORTING\n");
|
AsanReport("ABORTING\n");
|
||||||
__asan_print_accumulated_stats();
|
__asan_print_accumulated_stats();
|
||||||
Printf("Shadow byte and word:\n");
|
AsanPrintf("Shadow byte and word:\n");
|
||||||
Printf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
|
AsanPrintf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
|
||||||
uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
|
uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
|
||||||
PrintBytes(" ", (uptr*)(aligned_shadow));
|
PrintBytes(" ", (uptr*)(aligned_shadow));
|
||||||
Printf("More shadow bytes:\n");
|
AsanPrintf("More shadow bytes:\n");
|
||||||
PrintBytes(" ", (uptr*)(aligned_shadow-4*kWordSize));
|
PrintBytes(" ", (uptr*)(aligned_shadow-4*kWordSize));
|
||||||
PrintBytes(" ", (uptr*)(aligned_shadow-3*kWordSize));
|
PrintBytes(" ", (uptr*)(aligned_shadow-3*kWordSize));
|
||||||
PrintBytes(" ", (uptr*)(aligned_shadow-2*kWordSize));
|
PrintBytes(" ", (uptr*)(aligned_shadow-2*kWordSize));
|
||||||
|
|
|
@ -33,7 +33,7 @@ void AsanStackTrace::PrintStack(uptr *addr, uptr size) {
|
||||||
uptr pc = addr[i];
|
uptr pc = addr[i];
|
||||||
char buff[4096];
|
char buff[4096];
|
||||||
ASAN_USE_EXTERNAL_SYMBOLIZER((void*)pc, buff, sizeof(buff));
|
ASAN_USE_EXTERNAL_SYMBOLIZER((void*)pc, buff, sizeof(buff));
|
||||||
Printf(" #%zu 0x%zx %s\n", i, pc, buff);
|
AsanPrintf(" #%zu 0x%zx %s\n", i, pc, buff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,19 +51,19 @@ void AsanStackTrace::PrintStack(uptr *addr, uptr size) {
|
||||||
for (AddressInfoList *entry = address_info_list; entry;
|
for (AddressInfoList *entry = address_info_list; entry;
|
||||||
entry = entry->next) {
|
entry = entry->next) {
|
||||||
AddressInfo info = entry->info;
|
AddressInfo info = entry->info;
|
||||||
Printf(" #%zu 0x%zx %s:%d:%d\n", frame_num, pc,
|
AsanPrintf(" #%zu 0x%zx %s:%d:%d\n", frame_num, pc,
|
||||||
(info.file) ? info.file : "",
|
(info.file) ? info.file : "",
|
||||||
info.line, info.column);
|
info.line, info.column);
|
||||||
frame_num++;
|
frame_num++;
|
||||||
}
|
}
|
||||||
address_info_list->Clear();
|
address_info_list->Clear();
|
||||||
} else {
|
} else {
|
||||||
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
|
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
|
||||||
filename, sizeof(filename))) {
|
filename, sizeof(filename))) {
|
||||||
Printf(" #%zu 0x%zx (%s+0x%zx)\n", frame_num, pc, filename,
|
AsanPrintf(" #%zu 0x%zx (%s+0x%zx)\n", frame_num, pc, filename,
|
||||||
offset);
|
offset);
|
||||||
} else {
|
} else {
|
||||||
Printf(" #%zu 0x%zx\n", frame_num, pc);
|
AsanPrintf(" #%zu 0x%zx\n", frame_num, pc);
|
||||||
}
|
}
|
||||||
frame_num++;
|
frame_num++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,30 +27,30 @@ AsanStats::AsanStats() {
|
||||||
|
|
||||||
static void PrintMallocStatsArray(const char *prefix,
|
static void PrintMallocStatsArray(const char *prefix,
|
||||||
uptr (&array)[kNumberOfSizeClasses]) {
|
uptr (&array)[kNumberOfSizeClasses]) {
|
||||||
Printf("%s", prefix);
|
AsanPrintf("%s", prefix);
|
||||||
for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
|
for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
|
||||||
if (!array[i]) continue;
|
if (!array[i]) continue;
|
||||||
Printf("%zu:%zu; ", i, array[i]);
|
AsanPrintf("%zu:%zu; ", i, array[i]);
|
||||||
}
|
}
|
||||||
Printf("\n");
|
AsanPrintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsanStats::Print() {
|
void AsanStats::Print() {
|
||||||
Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
|
AsanPrintf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
|
||||||
malloced>>20, malloced_redzones>>20, mallocs);
|
malloced>>20, malloced_redzones>>20, mallocs);
|
||||||
Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
|
AsanPrintf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
|
||||||
Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
|
AsanPrintf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
|
||||||
Printf("Stats: %zuM really freed by %zu calls\n",
|
AsanPrintf("Stats: %zuM really freed by %zu calls\n",
|
||||||
really_freed>>20, real_frees);
|
really_freed>>20, real_frees);
|
||||||
Printf("Stats: %zuM (%zu full pages) mmaped in %zu calls\n",
|
AsanPrintf("Stats: %zuM (%zu full pages) mmaped in %zu calls\n",
|
||||||
mmaped>>20, mmaped / kPageSize, mmaps);
|
mmaped>>20, mmaped / kPageSize, mmaps);
|
||||||
|
|
||||||
PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size);
|
PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size);
|
||||||
PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
|
PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
|
||||||
PrintMallocStatsArray(" frees by size class: ", freed_by_size);
|
PrintMallocStatsArray(" frees by size class: ", freed_by_size);
|
||||||
PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size);
|
PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size);
|
||||||
Printf("Stats: malloc large: %zu small slow: %zu\n",
|
AsanPrintf("Stats: malloc large: %zu small slow: %zu\n",
|
||||||
malloc_large, malloc_small_slow);
|
malloc_large, malloc_small_slow);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AsanLock print_lock(LINKER_INITIALIZED);
|
static AsanLock print_lock(LINKER_INITIALIZED);
|
||||||
|
|
|
@ -41,7 +41,7 @@ class AsanThreadSummary {
|
||||||
if (tid_ == 0) return; // no need to announce the main thread.
|
if (tid_ == 0) return; // no need to announce the main thread.
|
||||||
if (!announced_) {
|
if (!announced_) {
|
||||||
announced_ = true;
|
announced_ = true;
|
||||||
Printf("Thread T%d created by T%d here:\n", tid_, parent_tid_);
|
AsanPrintf("Thread T%d created by T%d here:\n", tid_, parent_tid_);
|
||||||
stack_.PrintStack();
|
stack_.PrintStack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,10 @@ void RawWrite(const char *buffer);
|
||||||
void *MmapOrDie(uptr size);
|
void *MmapOrDie(uptr size);
|
||||||
void UnmapOrDie(void *addr, uptr size);
|
void UnmapOrDie(void *addr, uptr size);
|
||||||
|
|
||||||
|
void Printf(const char *format, ...) FORMAT(1, 2);
|
||||||
|
int SNPrintf(char *buffer, uptr length, const char *format, ...) FORMAT(3, 4);
|
||||||
|
void Report(const char *format, ...) FORMAT(1, 2);
|
||||||
|
|
||||||
// Bit twiddling.
|
// Bit twiddling.
|
||||||
inline bool IsPowerOfTwo(uptr x) {
|
inline bool IsPowerOfTwo(uptr x) {
|
||||||
return (x & (x - 1)) == 0;
|
return (x & (x - 1)) == 0;
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
//===-- sanitizer_printf.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 shared between AddressSanitizer and ThreadSanitizer.
|
||||||
|
//
|
||||||
|
// Internal printf function, used inside run-time libraries.
|
||||||
|
// We can't use libc printf because we intercept some of the functions used
|
||||||
|
// inside it.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
#include "sanitizer_common.h"
|
||||||
|
#include "sanitizer_libc.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
namespace __sanitizer {
|
||||||
|
|
||||||
|
static int AppendChar(char **buff, const char *buff_end, char c) {
|
||||||
|
if (*buff < buff_end) {
|
||||||
|
**buff = c;
|
||||||
|
(*buff)++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends number in a given base to buffer. If its length is less than
|
||||||
|
// "minimal_num_length", it is padded with leading zeroes.
|
||||||
|
static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
||||||
|
u8 base, u8 minimal_num_length) {
|
||||||
|
uptr const kMaxLen = 30;
|
||||||
|
RAW_CHECK(base == 10 || base == 16);
|
||||||
|
RAW_CHECK(minimal_num_length < kMaxLen);
|
||||||
|
uptr num_buffer[kMaxLen];
|
||||||
|
uptr pos = 0;
|
||||||
|
do {
|
||||||
|
RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
|
||||||
|
num_buffer[pos++] = num % base;
|
||||||
|
num /= base;
|
||||||
|
} while (num > 0);
|
||||||
|
while (pos < minimal_num_length) num_buffer[pos++] = 0;
|
||||||
|
int result = 0;
|
||||||
|
while (pos-- > 0) {
|
||||||
|
uptr digit = num_buffer[pos];
|
||||||
|
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
|
||||||
|
: 'a' + digit - 10);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num) {
|
||||||
|
int result = 0;
|
||||||
|
if (num < 0) {
|
||||||
|
result += AppendChar(buff, buff_end, '-');
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int AppendString(char **buff, const char *buff_end, const char *s) {
|
||||||
|
if (s == 0)
|
||||||
|
s = "<null>";
|
||||||
|
int result = 0;
|
||||||
|
for (; *s; s++) {
|
||||||
|
result += AppendChar(buff, buff_end, *s);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
|
||||||
|
int result = 0;
|
||||||
|
result += AppendString(buff, buff_end, "0x");
|
||||||
|
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
|
||||||
|
(__WORDSIZE == 64) ? 12 : 8);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VSNPrintf(char *buff, int buff_length,
|
||||||
|
const char *format, va_list args) {
|
||||||
|
static const char *kPrintfFormatsHelp = "Supported Printf formats: "
|
||||||
|
"%%[z]{d,u,x}; %%p; %%s\n";
|
||||||
|
RAW_CHECK(format);
|
||||||
|
RAW_CHECK(buff_length > 0);
|
||||||
|
const char *buff_end = &buff[buff_length - 1];
|
||||||
|
const char *cur = format;
|
||||||
|
int result = 0;
|
||||||
|
for (; *cur; cur++) {
|
||||||
|
if (*cur != '%') {
|
||||||
|
result += AppendChar(&buff, buff_end, *cur);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cur++;
|
||||||
|
bool have_z = (*cur == 'z');
|
||||||
|
cur += have_z;
|
||||||
|
s64 dval;
|
||||||
|
u64 uval;
|
||||||
|
switch (*cur) {
|
||||||
|
case 'd': {
|
||||||
|
dval = have_z ? va_arg(args, sptr)
|
||||||
|
: va_arg(args, int);
|
||||||
|
result += AppendSignedDecimal(&buff, buff_end, dval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'u':
|
||||||
|
case 'x': {
|
||||||
|
uval = have_z ? va_arg(args, uptr)
|
||||||
|
: va_arg(args, unsigned);
|
||||||
|
result += AppendUnsigned(&buff, buff_end, uval,
|
||||||
|
(*cur == 'u') ? 10 : 16, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p': {
|
||||||
|
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||||
|
result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||||
|
result += AppendString(&buff, buff_end, va_arg(args, char*));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '%' : {
|
||||||
|
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||||
|
result += AppendChar(&buff, buff_end, '%');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
RAW_CHECK_MSG(false, kPrintfFormatsHelp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RAW_CHECK(buff <= buff_end);
|
||||||
|
AppendChar(&buff, buff_end + 1, '\0');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printf(const char *format, ...) {
|
||||||
|
const int kLen = 1024 * 4;
|
||||||
|
char *buffer = (char*)MmapOrDie(kLen);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int needed_length = VSNPrintf(buffer, kLen, format, args);
|
||||||
|
va_end(args);
|
||||||
|
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
|
||||||
|
RawWrite(buffer);
|
||||||
|
UnmapOrDie(buffer, kLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes at most "length" symbols to "buffer" (including trailing '\0').
|
||||||
|
// Returns the number of symbols that should have been written to buffer
|
||||||
|
// (not including trailing '\0'). Thus, the string is truncated
|
||||||
|
// iff return value is not less than "length".
|
||||||
|
int SNPrintf(char *buffer, uptr length, const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int needed_length = VSNPrintf(buffer, length, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return needed_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like Printf, but prints the current PID before the output string.
|
||||||
|
void Report(const char *format, ...) {
|
||||||
|
const int kLen = 1024 * 4;
|
||||||
|
char *buffer = (char*)MmapOrDie(kLen);
|
||||||
|
int needed_length = SNPrintf(buffer, kLen, "==%d== ", GetPid());
|
||||||
|
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
needed_length += VSNPrintf(buffer + needed_length, kLen - needed_length,
|
||||||
|
format, args);
|
||||||
|
va_end(args);
|
||||||
|
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
||||||
|
RawWrite(buffer);
|
||||||
|
UnmapOrDie(buffer, kLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __sanitizer
|
|
@ -679,7 +679,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
|
||||||
// We place the huge ThreadState object into TLS, account for that.
|
// We place the huge ThreadState object into TLS, account for that.
|
||||||
const uptr minstacksize = GetTlsSize() + 128*1024;
|
const uptr minstacksize = GetTlsSize() + 128*1024;
|
||||||
if (stacksize < minstacksize) {
|
if (stacksize < minstacksize) {
|
||||||
DPrintf("ThreadSanitizer: stacksize %lu->%lu\n", stacksize, minstacksize);
|
DPrintf("ThreadSanitizer: stacksize %zu->%zu\n", stacksize, minstacksize);
|
||||||
pthread_attr_setstacksize(attr, minstacksize);
|
pthread_attr_setstacksize(attr, minstacksize);
|
||||||
}
|
}
|
||||||
ThreadParam p;
|
ThreadParam p;
|
||||||
|
|
|
@ -125,7 +125,7 @@ static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
|
||||||
ExpectRace *race = FindRace(list, addr, size);
|
ExpectRace *race = FindRace(list, addr, size);
|
||||||
if (race == 0)
|
if (race == 0)
|
||||||
return false;
|
return false;
|
||||||
DPrintf("Hit expected/benign race: %s addr=%lx:%d %s:%d\n",
|
DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
|
||||||
race->desc, race->addr, (int)race->size, race->file, race->line);
|
race->desc, race->addr, (int)race->size, race->file, race->line);
|
||||||
race->hitcount++;
|
race->hitcount++;
|
||||||
return true;
|
return true;
|
||||||
|
@ -217,7 +217,7 @@ void AnnotateNoOp(char *f, int l, uptr mem) {
|
||||||
static void ReportMissedExpectedRace(ExpectRace *race) {
|
static void ReportMissedExpectedRace(ExpectRace *race) {
|
||||||
TsanPrintf("==================\n");
|
TsanPrintf("==================\n");
|
||||||
TsanPrintf("WARNING: ThreadSanitizer: missed expected data race\n");
|
TsanPrintf("WARNING: ThreadSanitizer: missed expected data race\n");
|
||||||
TsanPrintf(" %s addr=%lx %s:%d\n",
|
TsanPrintf(" %s addr=%zx %s:%d\n",
|
||||||
race->desc, race->addr, race->file, race->line);
|
race->desc, race->addr, race->file, race->line);
|
||||||
TsanPrintf("==================\n");
|
TsanPrintf("==================\n");
|
||||||
}
|
}
|
||||||
|
@ -267,14 +267,14 @@ void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) {
|
||||||
Lock lock(&dyn_ann_ctx->mtx);
|
Lock lock(&dyn_ann_ctx->mtx);
|
||||||
AddExpectRace(&dyn_ann_ctx->expect,
|
AddExpectRace(&dyn_ann_ctx->expect,
|
||||||
f, l, mem, 1, desc);
|
f, l, mem, 1, desc);
|
||||||
DPrintf("Add expected race: %s addr=%lx %s:%d\n", desc, mem, f, l);
|
DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
|
static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
|
||||||
Lock lock(&dyn_ann_ctx->mtx);
|
Lock lock(&dyn_ann_ctx->mtx);
|
||||||
AddExpectRace(&dyn_ann_ctx->benign,
|
AddExpectRace(&dyn_ann_ctx->benign,
|
||||||
f, l, mem, size, desc);
|
f, l, mem, size, desc);
|
||||||
DPrintf("Add benign race: %s addr=%lx %s:%d\n", desc, mem, f, l);
|
DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
|
// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
|
||||||
|
|
|
@ -40,7 +40,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz) {
|
||||||
if (CTX() && CTX()->initialized) {
|
if (CTX() && CTX()->initialized) {
|
||||||
MemoryResetRange(thr, pc, (uptr)p, sz);
|
MemoryResetRange(thr, pc, (uptr)p, sz);
|
||||||
}
|
}
|
||||||
DPrintf("#%d: alloc(%lu) = %p\n", thr->tid, sz, p);
|
DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
|
||||||
SignalUnsafeCall(thr, pc);
|
SignalUnsafeCall(thr, pc);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ MBlock *user_mblock(ThreadState *thr, void *p) {
|
||||||
MBlock *b = (MBlock*)AllocBlock(p);
|
MBlock *b = (MBlock*)AllocBlock(p);
|
||||||
// FIXME: Output a warning, it's a user error.
|
// FIXME: Output a warning, it's a user error.
|
||||||
if (p < (char*)(b + 1) || p > (char*)(b + 1) + b->size) {
|
if (p < (char*)(b + 1) || p > (char*)(b + 1) + b->size) {
|
||||||
TsanPrintf("user_mblock p=%p b=%p size=%lu beg=%p end=%p\n",
|
TsanPrintf("user_mblock p=%p b=%p size=%zu beg=%p end=%p\n",
|
||||||
p, b, b->size, (char*)(b + 1), (char*)(b + 1) + b->size);
|
p, b, b->size, (char*)(b + 1), (char*)(b + 1) + b->size);
|
||||||
CHECK_GE(p, (char*)(b + 1));
|
CHECK_GE(p, (char*)(b + 1));
|
||||||
CHECK_LE(p, (char*)(b + 1) + b->size);
|
CHECK_LE(p, (char*)(b + 1) + b->size);
|
||||||
|
|
|
@ -120,7 +120,7 @@ DeadlockDetector::DeadlockDetector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadlockDetector::Lock(MutexType t) {
|
void DeadlockDetector::Lock(MutexType t) {
|
||||||
// TsanPrintf("LOCK %d @%llu\n", t, seq_ + 1);
|
// TsanPrintf("LOCK %d @%zu\n", t, seq_ + 1);
|
||||||
u64 max_seq = 0;
|
u64 max_seq = 0;
|
||||||
u64 max_idx = MutexTypeInvalid;
|
u64 max_idx = MutexTypeInvalid;
|
||||||
for (int i = 0; i != MutexTypeCount; i++) {
|
for (int i = 0; i != MutexTypeCount; i++) {
|
||||||
|
@ -135,16 +135,17 @@ void DeadlockDetector::Lock(MutexType t) {
|
||||||
locked_[t] = ++seq_;
|
locked_[t] = ++seq_;
|
||||||
if (max_idx == MutexTypeInvalid)
|
if (max_idx == MutexTypeInvalid)
|
||||||
return;
|
return;
|
||||||
// TsanPrintf(" last %d @%llu\n", max_idx, max_seq);
|
// TsanPrintf(" last %d @%zu\n", max_idx, max_seq);
|
||||||
if (!CanLockAdj[max_idx][t]) {
|
if (!CanLockAdj[max_idx][t]) {
|
||||||
TsanPrintf("ThreadSanitizer: internal deadlock detected\n");
|
TsanPrintf("ThreadSanitizer: internal deadlock detected\n");
|
||||||
TsanPrintf("ThreadSanitizer: can't lock %d while under %llu\n", t, max_idx);
|
TsanPrintf("ThreadSanitizer: can't lock %d while under %zu\n",
|
||||||
|
t, (uptr)max_idx);
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadlockDetector::Unlock(MutexType t) {
|
void DeadlockDetector::Unlock(MutexType t) {
|
||||||
// TsanPrintf("UNLO %d @%llu #%llu\n", t, seq_, locked_[t]);
|
// TsanPrintf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
|
||||||
CHECK(locked_[t]);
|
CHECK(locked_[t]);
|
||||||
locked_[t] = 0;
|
locked_[t] = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ static void ProtectRange(uptr beg, uptr end) {
|
||||||
PROT_NONE,
|
PROT_NONE,
|
||||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||||
-1, 0)) {
|
-1, 0)) {
|
||||||
TsanPrintf("FATAL: ThreadSanitizer can not protect [%lx,%lx]\n", beg, end);
|
TsanPrintf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
|
||||||
TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
|
TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
@ -120,17 +120,17 @@ void InitializeShadowMemory() {
|
||||||
}
|
}
|
||||||
ProtectRange(kClosedLowBeg, kClosedLowEnd);
|
ProtectRange(kClosedLowBeg, kClosedLowEnd);
|
||||||
ProtectRange(kClosedMidBeg, kClosedMidEnd);
|
ProtectRange(kClosedMidBeg, kClosedMidEnd);
|
||||||
DPrintf("kClosedLow %lx-%lx (%luGB)\n",
|
DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
|
||||||
kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
|
kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
|
||||||
DPrintf("kLinuxShadow %lx-%lx (%luGB)\n",
|
DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
|
||||||
kLinuxShadowBeg, kLinuxShadowEnd,
|
kLinuxShadowBeg, kLinuxShadowEnd,
|
||||||
(kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
|
(kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
|
||||||
DPrintf("kClosedMid %lx-%lx (%luGB)\n",
|
DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
|
||||||
kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
|
kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
|
||||||
DPrintf("kLinuxAppMem %lx-%lx (%luGB)\n",
|
DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
|
||||||
kLinuxAppMemBeg, kLinuxAppMemEnd,
|
kLinuxAppMemBeg, kLinuxAppMemEnd,
|
||||||
(kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
|
(kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
|
||||||
DPrintf("stack %lx\n", (uptr)&shadow);
|
DPrintf("stack %zx\n", (uptr)&shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckPIE() {
|
static void CheckPIE() {
|
||||||
|
@ -144,8 +144,8 @@ static void CheckPIE() {
|
||||||
u64 addr = strtoll(buf, 0, 16);
|
u64 addr = strtoll(buf, 0, 16);
|
||||||
if ((u64)addr < kLinuxAppMemBeg) {
|
if ((u64)addr < kLinuxAppMemBeg) {
|
||||||
TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
|
TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
|
||||||
"something is mapped at 0x%llx < 0x%lx)\n",
|
"something is mapped at 0x%zx < 0x%zx)\n",
|
||||||
addr, kLinuxAppMemBeg);
|
(uptr)addr, kLinuxAppMemBeg);
|
||||||
TsanPrintf("FATAL: Make sure to compile with -fPIE"
|
TsanPrintf("FATAL: Make sure to compile with -fPIE"
|
||||||
" and to link with -pie.\n");
|
" and to link with -pie.\n");
|
||||||
Die();
|
Die();
|
||||||
|
|
|
@ -18,114 +18,12 @@
|
||||||
|
|
||||||
#include <stdarg.h> // va_list
|
#include <stdarg.h> // va_list
|
||||||
|
|
||||||
typedef long long i64; // NOLINT
|
namespace __sanitizer {
|
||||||
typedef long iptr; // NOLINT
|
int VSNPrintf(char *buff, int buff_length, const char *format, va_list args);
|
||||||
|
} // namespace __sanitizer
|
||||||
|
|
||||||
namespace __tsan {
|
namespace __tsan {
|
||||||
|
|
||||||
static int AppendChar(char **buff, const char *buff_end, char c) {
|
|
||||||
if (*buff < buff_end) {
|
|
||||||
**buff = c;
|
|
||||||
(*buff)++;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
|
||||||
int base, uptr minimal_num_length) {
|
|
||||||
uptr const kMaxLen = 30;
|
|
||||||
uptr num_buffer[kMaxLen];
|
|
||||||
uptr pos = 0;
|
|
||||||
do {
|
|
||||||
num_buffer[pos++] = num % base;
|
|
||||||
num /= base;
|
|
||||||
} while (num > 0);
|
|
||||||
while (pos < minimal_num_length) num_buffer[pos++] = 0;
|
|
||||||
int result = 0;
|
|
||||||
while (pos-- > 0) {
|
|
||||||
uptr digit = num_buffer[pos];
|
|
||||||
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
|
|
||||||
: 'a' + digit - 10);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int AppendSignedDecimal(char **buff, const char *buff_end, i64 num) {
|
|
||||||
int result = 0;
|
|
||||||
if (num < 0) {
|
|
||||||
result += AppendChar(buff, buff_end, '-');
|
|
||||||
num = -num;
|
|
||||||
}
|
|
||||||
result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int AppendString(char **buff, const char *buff_end, const char *s) {
|
|
||||||
if (s == 0)
|
|
||||||
s = "<null>";
|
|
||||||
int result = 0;
|
|
||||||
for (; *s; s++) {
|
|
||||||
result += AppendChar(buff, buff_end, *s);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
|
|
||||||
int result = 0;
|
|
||||||
result += AppendString(buff, buff_end, "0x");
|
|
||||||
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
|
|
||||||
(sizeof(void*) == 8) ? 12 : 8); // NOLINT
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uptr VSNPrintf(char *buff, int buff_length,
|
|
||||||
const char *format, va_list args) {
|
|
||||||
const char *buff_end = &buff[buff_length - 1];
|
|
||||||
const char *cur = format;
|
|
||||||
int result = 0;
|
|
||||||
for (; *cur; cur++) {
|
|
||||||
if (*cur != '%') {
|
|
||||||
result += AppendChar(&buff, buff_end, *cur);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cur++;
|
|
||||||
bool is_long = (*cur == 'l');
|
|
||||||
cur += is_long;
|
|
||||||
bool is_llong = (*cur == 'l');
|
|
||||||
cur += is_llong;
|
|
||||||
switch (*cur) {
|
|
||||||
case 'd': {
|
|
||||||
i64 v = is_llong ? va_arg(args, i64)
|
|
||||||
: is_long ? va_arg(args, iptr)
|
|
||||||
: va_arg(args, int);
|
|
||||||
result += AppendSignedDecimal(&buff, buff_end, v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'u':
|
|
||||||
case 'x': {
|
|
||||||
u64 v = is_llong ? va_arg(args, u64)
|
|
||||||
: is_long ? va_arg(args, uptr)
|
|
||||||
: va_arg(args, unsigned);
|
|
||||||
result += AppendUnsigned(&buff, buff_end, v, *cur == 'u' ? 10: 16, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'p': {
|
|
||||||
result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 's': {
|
|
||||||
result += AppendString(&buff, buff_end, va_arg(args, char*));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
Die();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AppendChar(&buff, buff_end + 1, '\0');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TsanPrintf(const char *format, ...) {
|
void TsanPrintf(const char *format, ...) {
|
||||||
ScopedInRtl in_rtl;
|
ScopedInRtl in_rtl;
|
||||||
const uptr kMaxLen = 16 * 1024;
|
const uptr kMaxLen = 16 * 1024;
|
||||||
|
@ -138,12 +36,4 @@ void TsanPrintf(const char *format, ...) {
|
||||||
buffer, len < buffer.Size() ? len : buffer.Size() - 1);
|
buffer, len < buffer.Size() ? len : buffer.Size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr SNPrintf(char *buffer, uptr length, const char *format, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
uptr len = VSNPrintf(buffer, length, format, args);
|
|
||||||
va_end(args);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace __tsan
|
} // namespace __tsan
|
||||||
|
|
|
@ -70,10 +70,10 @@ static void PrintMop(const ReportMop *mop, bool first) {
|
||||||
|
|
||||||
static void PrintLocation(const ReportLocation *loc) {
|
static void PrintLocation(const ReportLocation *loc) {
|
||||||
if (loc->type == ReportLocationGlobal) {
|
if (loc->type == ReportLocationGlobal) {
|
||||||
TsanPrintf(" Location is global '%s' of size %lu at %lx %s:%d\n",
|
TsanPrintf(" Location is global '%s' of size %zu at %zx %s:%d\n",
|
||||||
loc->name, loc->size, loc->addr, loc->file, loc->line);
|
loc->name, loc->size, loc->addr, loc->file, loc->line);
|
||||||
} else if (loc->type == ReportLocationHeap) {
|
} else if (loc->type == ReportLocationHeap) {
|
||||||
TsanPrintf(" Location is heap of size %lu at %lx allocated "
|
TsanPrintf(" Location is heap of size %zu at %zx allocated "
|
||||||
"by thread %d:\n", loc->size, loc->addr, loc->tid);
|
"by thread %d:\n", loc->size, loc->addr, loc->tid);
|
||||||
PrintStack(loc->stack);
|
PrintStack(loc->stack);
|
||||||
} else if (loc->type == ReportLocationStack) {
|
} else if (loc->type == ReportLocationStack) {
|
||||||
|
|
|
@ -104,9 +104,9 @@ static void WriteMemoryProfile(char *buf, uptr buf_size, int num) {
|
||||||
uptr nsync = 0;
|
uptr nsync = 0;
|
||||||
uptr syncmem = CTX()->synctab.GetMemoryConsumption(&nsync);
|
uptr syncmem = CTX()->synctab.GetMemoryConsumption(&nsync);
|
||||||
|
|
||||||
SNPrintf(buf, buf_size, "%d: shadow=%luMB"
|
SNPrintf(buf, buf_size, "%d: shadow=%zuMB"
|
||||||
" thread=%luMB(total=%d/live=%d)"
|
" thread=%zuMB(total=%d/live=%d)"
|
||||||
" sync=%luMB(cnt=%lu)\n",
|
" sync=%zuMB(cnt=%zu)\n",
|
||||||
num,
|
num,
|
||||||
shadow >> 20,
|
shadow >> 20,
|
||||||
threadmem >> 20, nthread, nlivethread,
|
threadmem >> 20, nthread, nlivethread,
|
||||||
|
@ -359,17 +359,18 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
|
||||||
int kAccessSizeLog, bool kAccessIsWrite) {
|
int kAccessSizeLog, bool kAccessIsWrite) {
|
||||||
u64 *shadow_mem = (u64*)MemToShadow(addr);
|
u64 *shadow_mem = (u64*)MemToShadow(addr);
|
||||||
DPrintf2("#%d: tsan::OnMemoryAccess: @%p %p size=%d"
|
DPrintf2("#%d: tsan::OnMemoryAccess: @%p %p size=%d"
|
||||||
" is_write=%d shadow_mem=%p {%llx, %llx, %llx, %llx}\n",
|
" is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
|
||||||
(int)thr->fast_state.tid(), (void*)pc, (void*)addr,
|
(int)thr->fast_state.tid(), (void*)pc, (void*)addr,
|
||||||
(int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem,
|
(int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem,
|
||||||
shadow_mem[0], shadow_mem[1], shadow_mem[2], shadow_mem[3]);
|
(uptr)shadow_mem[0], (uptr)shadow_mem[1],
|
||||||
|
(uptr)shadow_mem[2], (uptr)shadow_mem[3]);
|
||||||
#if TSAN_DEBUG
|
#if TSAN_DEBUG
|
||||||
if (!IsAppMem(addr)) {
|
if (!IsAppMem(addr)) {
|
||||||
TsanPrintf("Access to non app mem %lx\n", addr);
|
TsanPrintf("Access to non app mem %zx\n", addr);
|
||||||
DCHECK(IsAppMem(addr));
|
DCHECK(IsAppMem(addr));
|
||||||
}
|
}
|
||||||
if (!IsShadowMem((uptr)shadow_mem)) {
|
if (!IsShadowMem((uptr)shadow_mem)) {
|
||||||
TsanPrintf("Bad shadow addr %p (%lx)\n", shadow_mem, addr);
|
TsanPrintf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||||
DCHECK(IsShadowMem((uptr)shadow_mem));
|
DCHECK(IsShadowMem((uptr)shadow_mem));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
namespace __tsan {
|
namespace __tsan {
|
||||||
|
|
||||||
void TsanPrintf(const char *format, ...) FORMAT(1, 2);
|
void TsanPrintf(const char *format, ...) FORMAT(1, 2);
|
||||||
uptr SNPrintf(char *buffer, uptr length, const char *format, ...) FORMAT(3, 4);
|
|
||||||
|
|
||||||
// FastState (from most significant bit):
|
// FastState (from most significant bit):
|
||||||
// unused : 1
|
// unused : 1
|
||||||
|
|
|
@ -22,7 +22,7 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
|
||||||
bool rw, bool recursive) {
|
bool rw, bool recursive) {
|
||||||
Context *ctx = CTX();
|
Context *ctx = CTX();
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexCreate %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
|
||||||
StatInc(thr, StatMutexCreate);
|
StatInc(thr, StatMutexCreate);
|
||||||
MemoryWrite1Byte(thr, pc, addr);
|
MemoryWrite1Byte(thr, pc, addr);
|
||||||
SyncVar *s = ctx->synctab.GetAndLock(thr, pc, addr, true);
|
SyncVar *s = ctx->synctab.GetAndLock(thr, pc, addr, true);
|
||||||
|
@ -34,7 +34,7 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
|
||||||
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
Context *ctx = CTX();
|
Context *ctx = CTX();
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexDestroy %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
|
||||||
StatInc(thr, StatMutexDestroy);
|
StatInc(thr, StatMutexDestroy);
|
||||||
MemoryWrite1Byte(thr, pc, addr);
|
MemoryWrite1Byte(thr, pc, addr);
|
||||||
SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
|
SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
|
||||||
|
@ -52,7 +52,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexLock %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
|
||||||
MemoryRead1Byte(thr, pc, addr);
|
MemoryRead1Byte(thr, pc, addr);
|
||||||
thr->fast_state.IncrementEpoch();
|
thr->fast_state.IncrementEpoch();
|
||||||
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeLock, addr);
|
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeLock, addr);
|
||||||
|
@ -81,7 +81,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexUnlock %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
|
||||||
MemoryRead1Byte(thr, pc, addr);
|
MemoryRead1Byte(thr, pc, addr);
|
||||||
thr->fast_state.IncrementEpoch();
|
thr->fast_state.IncrementEpoch();
|
||||||
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeUnlock, addr);
|
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeUnlock, addr);
|
||||||
|
@ -114,7 +114,7 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexReadLock %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
|
||||||
StatInc(thr, StatMutexReadLock);
|
StatInc(thr, StatMutexReadLock);
|
||||||
MemoryRead1Byte(thr, pc, addr);
|
MemoryRead1Byte(thr, pc, addr);
|
||||||
thr->fast_state.IncrementEpoch();
|
thr->fast_state.IncrementEpoch();
|
||||||
|
@ -130,7 +130,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexReadUnlock %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
|
||||||
StatInc(thr, StatMutexReadUnlock);
|
StatInc(thr, StatMutexReadUnlock);
|
||||||
MemoryRead1Byte(thr, pc, addr);
|
MemoryRead1Byte(thr, pc, addr);
|
||||||
thr->fast_state.IncrementEpoch();
|
thr->fast_state.IncrementEpoch();
|
||||||
|
@ -148,7 +148,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: MutexReadOrWriteUnlock %lx\n", thr->tid, addr);
|
DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
|
||||||
MemoryRead1Byte(thr, pc, addr);
|
MemoryRead1Byte(thr, pc, addr);
|
||||||
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
|
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
|
||||||
if (s->owner_tid == SyncVar::kInvalidTid) {
|
if (s->owner_tid == SyncVar::kInvalidTid) {
|
||||||
|
@ -189,7 +189,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
|
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: Acquire %lx\n", thr->tid, addr);
|
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
|
||||||
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, false);
|
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, false);
|
||||||
thr->clock.set(thr->tid, thr->fast_state.epoch());
|
thr->clock.set(thr->tid, thr->fast_state.epoch());
|
||||||
thr->clock.acquire(&s->clock);
|
thr->clock.acquire(&s->clock);
|
||||||
|
@ -199,7 +199,7 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
|
|
||||||
void Release(ThreadState *thr, uptr pc, uptr addr) {
|
void Release(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
DPrintf("#%d: Release %lx\n", thr->tid, addr);
|
DPrintf("#%d: Release %zx\n", thr->tid, addr);
|
||||||
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
|
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
|
||||||
thr->clock.set(thr->tid, thr->fast_state.epoch());
|
thr->clock.set(thr->tid, thr->fast_state.epoch());
|
||||||
thr->clock.release(&s->clock);
|
thr->clock.release(&s->clock);
|
||||||
|
|
|
@ -68,7 +68,7 @@ static void StackStripMain(ReportStack *stack) {
|
||||||
// can actually happen if we do not instrument some code,
|
// can actually happen if we do not instrument some code,
|
||||||
// so it's only a DCHECK. However we must try hard to not miss it
|
// so it's only a DCHECK. However we must try hard to not miss it
|
||||||
// due to our fault.
|
// due to our fault.
|
||||||
TsanPrintf("Bottom stack frame of stack %lx is missed\n", stack->pc);
|
TsanPrintf("Bottom stack frame of stack %zx is missed\n", stack->pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,19 +189,19 @@ static void RestoreStack(int tid, const u64 epoch, StackTrace *stk) {
|
||||||
return;
|
return;
|
||||||
const u64 eend = epoch % kTraceSize;
|
const u64 eend = epoch % kTraceSize;
|
||||||
const u64 ebegin = eend / kTracePartSize * kTracePartSize;
|
const u64 ebegin = eend / kTracePartSize * kTracePartSize;
|
||||||
DPrintf("#%d: RestoreStack epoch=%llu ebegin=%llu eend=%llu partidx=%d\n",
|
DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
|
||||||
tid, epoch, ebegin, eend, partidx);
|
tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
|
||||||
InternalScopedBuf<uptr> stack(1024); // FIXME: de-hardcode 1024
|
InternalScopedBuf<uptr> stack(1024); // FIXME: de-hardcode 1024
|
||||||
for (uptr i = 0; i < hdr->stack0.Size(); i++) {
|
for (uptr i = 0; i < hdr->stack0.Size(); i++) {
|
||||||
stack[i] = hdr->stack0.Get(i);
|
stack[i] = hdr->stack0.Get(i);
|
||||||
DPrintf2(" #%02lu: pc=%lx\n", i, stack[i]);
|
DPrintf2(" #%02lu: pc=%zx\n", i, stack[i]);
|
||||||
}
|
}
|
||||||
uptr pos = hdr->stack0.Size();
|
uptr pos = hdr->stack0.Size();
|
||||||
for (uptr i = ebegin; i <= eend; i++) {
|
for (uptr i = ebegin; i <= eend; i++) {
|
||||||
Event ev = trace->events[i];
|
Event ev = trace->events[i];
|
||||||
EventType typ = (EventType)(ev >> 61);
|
EventType typ = (EventType)(ev >> 61);
|
||||||
uptr pc = (uptr)(ev & 0xffffffffffffull);
|
uptr pc = (uptr)(ev & 0xffffffffffffull);
|
||||||
DPrintf2(" %lu typ=%d pc=%lx\n", i, typ, pc);
|
DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc);
|
||||||
if (typ == EventTypeMop) {
|
if (typ == EventTypeMop) {
|
||||||
stack[pos] = pc;
|
stack[pos] = pc;
|
||||||
} else if (typ == EventTypeFuncEnter) {
|
} else if (typ == EventTypeFuncEnter) {
|
||||||
|
@ -213,7 +213,7 @@ static void RestoreStack(int tid, const u64 epoch, StackTrace *stk) {
|
||||||
pos--;
|
pos--;
|
||||||
}
|
}
|
||||||
for (uptr j = 0; j <= pos; j++)
|
for (uptr j = 0; j <= pos; j++)
|
||||||
DPrintf2(" #%lu: %lx\n", j, stack[j]);
|
DPrintf2(" #%zu: %zx\n", j, stack[j]);
|
||||||
}
|
}
|
||||||
if (pos == 0 && stack[0] == 0)
|
if (pos == 0 && stack[0] == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -349,8 +349,8 @@ void ReportRace(ThreadState *thr) {
|
||||||
|
|
||||||
void CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) {
|
void CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) {
|
||||||
ScopedInRtl in_rtl;
|
ScopedInRtl in_rtl;
|
||||||
TsanPrintf("FATAL: ThreadSanitizer CHECK failed: %s:%d \"%s\" (%llx, %llx)\n",
|
TsanPrintf("FATAL: ThreadSanitizer CHECK failed: %s:%d \"%s\" (%zx, %zx)\n",
|
||||||
file, line, cond, v1, v2);
|
file, line, cond, (uptr)v1, (uptr)v2);
|
||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ static void ThreadDead(ThreadState *thr, ThreadContext *tctx) {
|
||||||
CHECK_GT(thr->in_rtl, 0);
|
CHECK_GT(thr->in_rtl, 0);
|
||||||
CHECK(tctx->status == ThreadStatusRunning
|
CHECK(tctx->status == ThreadStatusRunning
|
||||||
|| tctx->status == ThreadStatusFinished);
|
|| tctx->status == ThreadStatusFinished);
|
||||||
DPrintf("#%d: ThreadDead uid=%lu\n", thr->tid, tctx->user_id);
|
DPrintf("#%d: ThreadDead uid=%zu\n", thr->tid, tctx->user_id);
|
||||||
tctx->status = ThreadStatusDead;
|
tctx->status = ThreadStatusDead;
|
||||||
tctx->user_id = 0;
|
tctx->user_id = 0;
|
||||||
tctx->sync.Reset();
|
tctx->sync.Reset();
|
||||||
|
@ -106,7 +106,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
|
||||||
CHECK_NE(tctx, 0);
|
CHECK_NE(tctx, 0);
|
||||||
CHECK_GE(tid, 0);
|
CHECK_GE(tid, 0);
|
||||||
CHECK_LT(tid, kMaxTid);
|
CHECK_LT(tid, kMaxTid);
|
||||||
DPrintf("#%d: ThreadCreate tid=%d uid=%lu\n", thr->tid, tid, uid);
|
DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
|
||||||
CHECK_EQ(tctx->status, ThreadStatusInvalid);
|
CHECK_EQ(tctx->status, ThreadStatusInvalid);
|
||||||
ctx->alive_threads++;
|
ctx->alive_threads++;
|
||||||
if (ctx->max_alive_threads < ctx->alive_threads) {
|
if (ctx->max_alive_threads < ctx->alive_threads) {
|
||||||
|
@ -170,9 +170,9 @@ void ThreadStart(ThreadState *thr, int tid) {
|
||||||
thr->clock.set(tid, tctx->epoch0);
|
thr->clock.set(tid, tctx->epoch0);
|
||||||
thr->clock.acquire(&tctx->sync);
|
thr->clock.acquire(&tctx->sync);
|
||||||
StatInc(thr, StatSyncAcquire);
|
StatInc(thr, StatSyncAcquire);
|
||||||
DPrintf("#%d: ThreadStart epoch=%llu stk_addr=%lx stk_size=%lx "
|
DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
|
||||||
"tls_addr=%lx tls_size=%lx\n",
|
"tls_addr=%zx tls_size=%zx\n",
|
||||||
tid, tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size);
|
tid, (uptr)tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadFinish(ThreadState *thr) {
|
void ThreadFinish(ThreadState *thr) {
|
||||||
|
@ -239,7 +239,7 @@ int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DPrintf("#%d: ThreadTid uid=%lu tid=%d\n", thr->tid, uid, res);
|
DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,20 +292,20 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
||||||
|
|
||||||
#if TSAN_DEBUG
|
#if TSAN_DEBUG
|
||||||
if (!IsAppMem(addr)) {
|
if (!IsAppMem(addr)) {
|
||||||
TsanPrintf("Access to non app mem %lx\n", addr);
|
TsanPrintf("Access to non app mem %zx\n", addr);
|
||||||
DCHECK(IsAppMem(addr));
|
DCHECK(IsAppMem(addr));
|
||||||
}
|
}
|
||||||
if (!IsAppMem(addr + size - 1)) {
|
if (!IsAppMem(addr + size - 1)) {
|
||||||
TsanPrintf("Access to non app mem %lx\n", addr + size - 1);
|
TsanPrintf("Access to non app mem %zx\n", addr + size - 1);
|
||||||
DCHECK(IsAppMem(addr + size - 1));
|
DCHECK(IsAppMem(addr + size - 1));
|
||||||
}
|
}
|
||||||
if (!IsShadowMem((uptr)shadow_mem)) {
|
if (!IsShadowMem((uptr)shadow_mem)) {
|
||||||
TsanPrintf("Bad shadow addr %p (%lx)\n", shadow_mem, addr);
|
TsanPrintf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||||
DCHECK(IsShadowMem((uptr)shadow_mem));
|
DCHECK(IsShadowMem((uptr)shadow_mem));
|
||||||
}
|
}
|
||||||
if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
|
if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
|
||||||
TsanPrintf("Bad shadow addr %p (%lx)\n",
|
TsanPrintf("Bad shadow addr %p (%zx)\n",
|
||||||
shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
|
shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
|
||||||
DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
|
DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -243,7 +243,7 @@ void StatOutput(u64 *stat) {
|
||||||
|
|
||||||
TsanPrintf("Statistics:\n");
|
TsanPrintf("Statistics:\n");
|
||||||
for (int i = 0; i < StatCnt; i++)
|
for (int i = 0; i < StatCnt; i++)
|
||||||
TsanPrintf("%s: %llu\n", name[i], stat[i]);
|
TsanPrintf("%s: %zu\n", name[i], (uptr)stat[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace __tsan
|
} // namespace __tsan
|
||||||
|
|
|
@ -102,13 +102,14 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
||||||
m->base = (uptr)info->dlpi_addr;
|
m->base = (uptr)info->dlpi_addr;
|
||||||
m->inp_fd = -1;
|
m->inp_fd = -1;
|
||||||
m->out_fd = -1;
|
m->out_fd = -1;
|
||||||
DPrintf("Module %s %lx\n", m->name, m->base);
|
DPrintf("Module %s %zx\n", m->name, m->base);
|
||||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||||
const Elf64_Phdr *s = &info->dlpi_phdr[i];
|
const Elf64_Phdr *s = &info->dlpi_phdr[i];
|
||||||
DPrintf(" Section p_type=%llx p_offset=%llx p_vaddr=%llx p_paddr=%llx"
|
DPrintf(" Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx"
|
||||||
" p_filesz=%llx p_memsz=%llx p_flags=%llx p_align=%llx\n",
|
" p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n",
|
||||||
(u64)s->p_type, (u64)s->p_offset, (u64)s->p_vaddr, (u64)s->p_paddr,
|
(uptr)s->p_type, (uptr)s->p_offset, (uptr)s->p_vaddr,
|
||||||
(u64)s->p_filesz, (u64)s->p_memsz, (u64)s->p_flags, (u64)s->p_align);
|
(uptr)s->p_paddr, (uptr)s->p_filesz, (uptr)s->p_memsz,
|
||||||
|
(uptr)s->p_flags, (uptr)s->p_align);
|
||||||
if (s->p_type != PT_LOAD)
|
if (s->p_type != PT_LOAD)
|
||||||
continue;
|
continue;
|
||||||
SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack,
|
SectionDesc *sec = (SectionDesc*)internal_alloc(MBlockReportStack,
|
||||||
|
@ -118,7 +119,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
||||||
sec->end = sec->base + s->p_memsz;
|
sec->end = sec->base + s->p_memsz;
|
||||||
sec->next = ctx->sections;
|
sec->next = ctx->sections;
|
||||||
ctx->sections = sec;
|
ctx->sections = sec;
|
||||||
DPrintf(" Section %lx-%lx\n", sec->base, sec->end);
|
DPrintf(" Section %zx-%zx\n", sec->base, sec->end);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +200,7 @@ ReportStack *SymbolizeData(uptr addr) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
InternalScopedBuf<char> cmd(1024);
|
InternalScopedBuf<char> cmd(1024);
|
||||||
SNPrintf(cmd, cmd.Size(),
|
SNPrintf(cmd, cmd.Size(),
|
||||||
"nm -alC %s|grep \"%lx\"|awk '{printf(\"%%s\\n%%s\", $3, $4)}' > tsan.tmp2",
|
"nm -alC %s|grep \"%zx\"|awk '{printf(\"%%s\\n%%s\", $3, $4)}' > tsan.tmp2",
|
||||||
exe, (addr - base));
|
exe, (addr - base));
|
||||||
if (system(cmd))
|
if (system(cmd))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -23,8 +23,8 @@ static void TestThreadInfo(bool main) {
|
||||||
uptr tls_addr = 0;
|
uptr tls_addr = 0;
|
||||||
uptr tls_size = 0;
|
uptr tls_size = 0;
|
||||||
GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||||
// Printf("stk=%lx-%lx(%lu)\n", stk_addr, stk_addr + stk_size, stk_size);
|
// Printf("stk=%zx-%zx(%zu)\n", stk_addr, stk_addr + stk_size, stk_size);
|
||||||
// Printf("tls=%lx-%lx(%lu)\n", tls_addr, tls_addr + tls_size, tls_size);
|
// Printf("tls=%zx-%zx(%zu)\n", tls_addr, tls_addr + tls_size, tls_size);
|
||||||
|
|
||||||
int stack_var;
|
int stack_var;
|
||||||
EXPECT_NE(stk_addr, (uptr)0);
|
EXPECT_NE(stk_addr, (uptr)0);
|
||||||
|
|
|
@ -21,13 +21,13 @@ namespace __tsan {
|
||||||
TEST(Printf, Basic) {
|
TEST(Printf, Basic) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
uptr len = SNPrintf(buf, sizeof(buf),
|
uptr len = SNPrintf(buf, sizeof(buf),
|
||||||
"a%db%ldc%lldd%ue%luf%llug%xh%lxq%llxw%pe%sr",
|
"a%db%zdc%ue%zuf%xh%zxq%pe%sr",
|
||||||
(int)-1, (long)-2, (long long)-3, // NOLINT
|
(int)-1, (long)-2, // NOLINT
|
||||||
(unsigned)-4, (unsigned long)5, (unsigned long long)6, // NOLINT
|
(unsigned)-4, (unsigned long)5, // NOLINT
|
||||||
(unsigned)10, (unsigned long)11, (unsigned long long)12, // NOLINT
|
(unsigned)10, (unsigned long)11, // NOLINT
|
||||||
(void*)0x123, "_string_");
|
(void*)0x123, "_string_");
|
||||||
EXPECT_EQ(len, strlen(buf));
|
EXPECT_EQ(len, strlen(buf));
|
||||||
EXPECT_EQ(0, strcmp(buf, "a-1b-2c-3d4294967292e5f6gahbqcw"
|
EXPECT_EQ(0, strcmp(buf, "a-1b-2c4294967292e5fahbq"
|
||||||
"0x000000000123e_string_r"));
|
"0x000000000123e_string_r"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ TEST(Printf, OverflowInt) {
|
||||||
|
|
||||||
TEST(Printf, OverflowUint) {
|
TEST(Printf, OverflowUint) {
|
||||||
char buf[] = "123456789";
|
char buf[] = "123456789";
|
||||||
SNPrintf(buf, 4, "a%llx", (long long)0x123456789); // NOLINT
|
SNPrintf(buf, 4, "a%zx", (unsigned long)0x123456789); // NOLINT
|
||||||
EXPECT_EQ(0, strcmp(buf, "a12"));
|
EXPECT_EQ(0, strcmp(buf, "a12"));
|
||||||
EXPECT_EQ(buf[3], 0);
|
EXPECT_EQ(buf[3], 0);
|
||||||
EXPECT_EQ(buf[4], '5');
|
EXPECT_EQ(buf[4], '5');
|
||||||
|
@ -96,14 +96,11 @@ static void TestMinMax(const char *fmt, T min, T max) {
|
||||||
|
|
||||||
TEST(Printf, MinMax) {
|
TEST(Printf, MinMax) {
|
||||||
TestMinMax<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
|
TestMinMax<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
|
||||||
TestMinMax<long>("%ld-%ld", LONG_MIN, LONG_MAX); // NOLINT
|
TestMinMax<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
|
||||||
TestMinMax<long long>("%lld-%lld", LLONG_MIN, LLONG_MAX); // NOLINT
|
|
||||||
TestMinMax<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
|
TestMinMax<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
|
||||||
TestMinMax<unsigned long>("%lu-%lu", 0, ULONG_MAX); // NOLINT
|
TestMinMax<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
|
||||||
TestMinMax<unsigned long long>("%llu-%llu", 0, ULLONG_MAX); // NOLINT
|
|
||||||
TestMinMax<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
|
TestMinMax<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
|
||||||
TestMinMax<unsigned long>("%lx-%lx", 0, ULONG_MAX); // NOLINT
|
TestMinMax<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
|
||||||
TestMinMax<unsigned long long>("%llx-%llx", 0, ULLONG_MAX); // NOLINT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace __tsan
|
} // namespace __tsan
|
||||||
|
|
Loading…
Reference in New Issue