libsanitizer merge from upstream r253555.
libsanitizer/ 2015-11-23 Maxim Ostapenko <m.ostapenko@partner.samsung.com> * All source files: Merge from upstream r253555. * configure.tgt: Enable LSan on aarch64-*-linux* targets. Add new dependences for TSan for aarch64-*-linux* targets. * tsan/Makefile.am: Add new source files. * configure: Regenerate. * tsan/Makefile.in: Likewise. From-SVN: r230739
This commit is contained in:
parent
096b85f4b4
commit
55aea9f56c
@ -1,3 +1,12 @@
|
||||
2015-11-23 Maxim Ostapenko <m.ostapenko@partner.samsung.com>
|
||||
|
||||
* All source files: Merge from upstream r253555.
|
||||
* configure.tgt: Enable LSan on aarch64-*-linux* targets. Add new
|
||||
dependences for TSan for aarch64-*-linux* targets.
|
||||
* tsan/Makefile.am: Add new source files.
|
||||
* configure: Regenerate.
|
||||
* tsan/Makefile.in: Likewise.
|
||||
|
||||
2015-11-09 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* sanitizer_common/sanitizer_common_interceptors.inc: Update size
|
||||
|
@ -1,4 +1,4 @@
|
||||
250806
|
||||
253555
|
||||
|
||||
The first line of this file holds the svn revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
@ -73,6 +73,7 @@ ASAN_FLAG(bool, check_malloc_usable_size, true,
|
||||
"295.*.")
|
||||
ASAN_FLAG(bool, unmap_shadow_on_exit, false,
|
||||
"If set, explicitly unmaps the (huge) shadow at exit.")
|
||||
ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap")
|
||||
ASAN_FLAG(bool, print_stats, false,
|
||||
"Print various statistics after printing an error message or if "
|
||||
"atexit=1.")
|
||||
@ -132,3 +133,6 @@ ASAN_FLAG(int, detect_odr_violation, 2,
|
||||
ASAN_FLAG(bool, dump_instruction_bytes, false,
|
||||
"If true, dump 16 bytes starting at the instruction that caused SEGV")
|
||||
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
|
||||
ASAN_FLAG(bool, halt_on_error, true,
|
||||
"Crash the program after printing the first error report "
|
||||
"(WARNING: USE AT YOUR OWN RISK!)")
|
||||
|
@ -73,7 +73,7 @@ struct AsanInterceptorContext {
|
||||
} \
|
||||
if (!suppressed) { \
|
||||
GET_CURRENT_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \
|
||||
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -165,6 +165,19 @@ extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp);
|
||||
|
@ -31,17 +31,17 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h> // for dladdr()
|
||||
#include <fcntl.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h> // for free()
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h> // for free()
|
||||
#include <unistd.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
namespace __asan {
|
||||
|
||||
|
@ -13,348 +13,51 @@
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_MAC
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <dlfcn.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "sanitizer_common/sanitizer_mac.h"
|
||||
|
||||
// Similar code is used in Google Perftools,
|
||||
// http://code.google.com/p/google-perftools.
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// TODO(glider): do we need both zones?
|
||||
static malloc_zone_t *system_malloc_zone = 0;
|
||||
static malloc_zone_t asan_zone;
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
|
||||
vm_size_t start_size, unsigned zone_flags) {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
|
||||
malloc_zone_t *new_zone =
|
||||
(malloc_zone_t*)asan_memalign(page_size, allocated_size,
|
||||
&stack, FROM_MALLOC);
|
||||
internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
|
||||
new_zone->zone_name = NULL; // The name will be changed anyway.
|
||||
if (GetMacosVersion() >= MACOS_VERSION_LION) {
|
||||
// Prevent the client app from overwriting the zone contents.
|
||||
// Library functions that need to modify the zone will set PROT_WRITE on it.
|
||||
// This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
|
||||
mprotect(new_zone, allocated_size, PROT_READ);
|
||||
}
|
||||
return new_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
|
||||
ENSURE_ASAN_INITED();
|
||||
return &asan_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
|
||||
// FIXME: ASan should support purgeable allocations.
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=139
|
||||
ENSURE_ASAN_INITED();
|
||||
return &asan_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
ENSURE_ASAN_INITED();
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
ENSURE_ASAN_INITED();
|
||||
// Must return 0 if the contents were not purged since the last call to
|
||||
// malloc_make_purgeable().
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
|
||||
ENSURE_ASAN_INITED();
|
||||
// Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
|
||||
size_t buflen = 6 + (name ? internal_strlen(name) : 0);
|
||||
InternalScopedString new_name(buflen);
|
||||
if (name && zone->introspect == asan_zone.introspect) {
|
||||
new_name.append("asan-%s", name);
|
||||
name = new_name.data();
|
||||
}
|
||||
|
||||
// Call the system malloc's implementation for both external and our zones,
|
||||
// since that appropriately changes VM region protections on the zone.
|
||||
REAL(malloc_set_zone_name)(zone, name);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, malloc, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *res = asan_malloc(size, &stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!ptr) return;
|
||||
GET_STACK_TRACE_FREE;
|
||||
using namespace __asan;
|
||||
#define COMMON_MALLOC_ZONE_NAME "asan"
|
||||
#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
|
||||
#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
|
||||
#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
|
||||
#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
|
||||
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = asan_memalign(alignment, size, &stack, FROM_MALLOC)
|
||||
#define COMMON_MALLOC_MALLOC(size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = asan_malloc(size, &stack)
|
||||
#define COMMON_MALLOC_REALLOC(ptr, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = asan_realloc(ptr, size, &stack);
|
||||
#define COMMON_MALLOC_CALLOC(count, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = asan_calloc(count, size, &stack);
|
||||
#define COMMON_MALLOC_VALLOC(size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
|
||||
#define COMMON_MALLOC_FREE(ptr) \
|
||||
GET_STACK_TRACE_FREE; \
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, valloc, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
return asan_zone.introspect->good_size(&asan_zone, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
CHECK(memptr);
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
|
||||
if (result) {
|
||||
*memptr = result;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(glider): the __asan_mz_* functions should be united with the Linux
|
||||
// wrappers, as they are basically copied from there.
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
size_t __asan_mz_size(malloc_zone_t* zone, const void* ptr) {
|
||||
return asan_mz_size(ptr);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_mz_malloc(malloc_zone_t *zone, uptr size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_malloc(system_malloc_zone, size);
|
||||
}
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const size_t kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static size_t allocated;
|
||||
size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
allocated += size_in_words;
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_mz_valloc(malloc_zone_t *zone, size_t size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_valloc(system_malloc_zone, size);
|
||||
}
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
#define GET_ZONE_FOR_PTR(ptr) \
|
||||
malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
|
||||
const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
|
||||
|
||||
void ALWAYS_INLINE free_common(void *context, void *ptr) {
|
||||
if (!ptr) return;
|
||||
GET_STACK_TRACE_FREE;
|
||||
// FIXME: need to retire this flag.
|
||||
if (!flags()->mac_ignore_invalid_free) {
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
} else {
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(glider): the allocation callbacks need to be refactored.
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_mz_free(malloc_zone_t *zone, void *ptr) {
|
||||
free_common(zone, ptr);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
|
||||
if (!ptr) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
} else {
|
||||
if (asan_mz_size(ptr)) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
} else {
|
||||
// We can't recover from reallocating an unknown address, because
|
||||
// this would require reading at most |size| bytes from
|
||||
// potentially unaccessible memory.
|
||||
GET_STACK_TRACE_FREE;
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_mz_destroy(malloc_zone_t* zone) {
|
||||
// A no-op -- we will not be destroyed!
|
||||
Report("__asan_mz_destroy() called -- ignoring\n");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_memalign(system_malloc_zone, align, size);
|
||||
}
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_memalign(align, size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
// This function is currently unused, and we build with -Werror.
|
||||
#if 0
|
||||
void __asan_mz_free_definite_size(
|
||||
malloc_zone_t* zone, void *ptr, size_t size) {
|
||||
// TODO(glider): check that |size| is valid.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
#endif
|
||||
|
||||
kern_return_t mi_enumerator(task_t task, void *,
|
||||
unsigned type_mask, vm_address_t zone_address,
|
||||
memory_reader_t reader,
|
||||
vm_range_recorder_t recorder) {
|
||||
// Should enumerate all the pointers we have. Seems like a lot of work.
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
size_t mi_good_size(malloc_zone_t *zone, size_t size) {
|
||||
// I think it's always safe to return size, but we maybe could do better.
|
||||
return size;
|
||||
}
|
||||
|
||||
boolean_t mi_check(malloc_zone_t *zone) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void mi_print(malloc_zone_t *zone, boolean_t verbose) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void mi_log(malloc_zone_t *zone, void *address) {
|
||||
// I don't think we support anything like this
|
||||
}
|
||||
|
||||
void mi_force_lock(malloc_zone_t *zone) {
|
||||
asan_mz_force_lock();
|
||||
}
|
||||
|
||||
void mi_force_unlock(malloc_zone_t *zone) {
|
||||
asan_mz_force_unlock();
|
||||
}
|
||||
|
||||
void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
|
||||
AsanMallocStats malloc_stats;
|
||||
FillMallocStatistics(&malloc_stats);
|
||||
CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
|
||||
#define COMMON_MALLOC_SIZE(ptr) \
|
||||
uptr size = asan_mz_size(ptr);
|
||||
#define COMMON_MALLOC_FILL_STATS(zone, stats) \
|
||||
AsanMallocStats malloc_stats; \
|
||||
FillMallocStatistics(&malloc_stats); \
|
||||
CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats)); \
|
||||
internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
|
||||
}
|
||||
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
|
||||
GET_STACK_TRACE_FREE; \
|
||||
ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
#define COMMON_MALLOC_IGNORE_INVALID_FREE flags()->mac_ignore_invalid_free
|
||||
#define COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name) \
|
||||
GET_STACK_TRACE_FREE; \
|
||||
WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
#define COMMON_MALLOC_NAMESPACE __asan
|
||||
|
||||
boolean_t mi_zone_locked(malloc_zone_t *zone) {
|
||||
// UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
#include "sanitizer_common/sanitizer_malloc_mac.inc"
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void ReplaceSystemMalloc() {
|
||||
static malloc_introspection_t asan_introspection;
|
||||
// Ok to use internal_memset, these places are not performance-critical.
|
||||
internal_memset(&asan_introspection, 0, sizeof(asan_introspection));
|
||||
|
||||
asan_introspection.enumerator = &mi_enumerator;
|
||||
asan_introspection.good_size = &mi_good_size;
|
||||
asan_introspection.check = &mi_check;
|
||||
asan_introspection.print = &mi_print;
|
||||
asan_introspection.log = &mi_log;
|
||||
asan_introspection.force_lock = &mi_force_lock;
|
||||
asan_introspection.force_unlock = &mi_force_unlock;
|
||||
asan_introspection.statistics = &mi_statistics;
|
||||
asan_introspection.zone_locked = &mi_zone_locked;
|
||||
|
||||
internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
|
||||
|
||||
// Use version 6 for OSX >= 10.6.
|
||||
asan_zone.version = 6;
|
||||
asan_zone.zone_name = "asan";
|
||||
asan_zone.size = &__asan_mz_size;
|
||||
asan_zone.malloc = &__asan_mz_malloc;
|
||||
asan_zone.calloc = &__asan_mz_calloc;
|
||||
asan_zone.valloc = &__asan_mz_valloc;
|
||||
asan_zone.free = &__asan_mz_free;
|
||||
asan_zone.realloc = &__asan_mz_realloc;
|
||||
asan_zone.destroy = &__asan_mz_destroy;
|
||||
asan_zone.batch_malloc = 0;
|
||||
asan_zone.batch_free = 0;
|
||||
asan_zone.free_definite_size = 0;
|
||||
asan_zone.memalign = &__asan_mz_memalign;
|
||||
asan_zone.introspect = &asan_introspection;
|
||||
|
||||
// Register the ASan zone.
|
||||
malloc_zone_register(&asan_zone);
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
#endif
|
||||
|
@ -116,11 +116,7 @@ static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kIosShadowOffset64 = 0x130000000;
|
||||
static const u64 kIosSimShadowOffset32 = 1ULL << 30;
|
||||
static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64;
|
||||
#if SANITIZER_AARCH64_VMA == 39
|
||||
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
|
||||
#elif SANITIZER_AARCH64_VMA == 42
|
||||
static const u64 kAArch64_ShadowOffset64 = 1ULL << 39;
|
||||
#endif
|
||||
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
|
||||
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
|
||||
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
|
||||
|
@ -373,10 +373,10 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
|
||||
}
|
||||
}
|
||||
|
||||
int __sanitizer_verify_contiguous_container(const void *beg_p,
|
||||
const void *mid_p,
|
||||
const void *end_p) {
|
||||
if (!flags()->detect_container_overflow) return 1;
|
||||
const void *__sanitizer_contiguous_container_find_bad_address(
|
||||
const void *beg_p, const void *mid_p, const void *end_p) {
|
||||
if (!flags()->detect_container_overflow)
|
||||
return nullptr;
|
||||
uptr beg = reinterpret_cast<uptr>(beg_p);
|
||||
uptr end = reinterpret_cast<uptr>(end_p);
|
||||
uptr mid = reinterpret_cast<uptr>(mid_p);
|
||||
@ -393,17 +393,24 @@ int __sanitizer_verify_contiguous_container(const void *beg_p,
|
||||
uptr r3_end = end;
|
||||
for (uptr i = r1_beg; i < r1_end; i++)
|
||||
if (AddressIsPoisoned(i))
|
||||
return 0;
|
||||
return reinterpret_cast<const void *>(i);
|
||||
for (uptr i = r2_beg; i < mid; i++)
|
||||
if (AddressIsPoisoned(i))
|
||||
return 0;
|
||||
return reinterpret_cast<const void *>(i);
|
||||
for (uptr i = mid; i < r2_end; i++)
|
||||
if (!AddressIsPoisoned(i))
|
||||
return 0;
|
||||
return reinterpret_cast<const void *>(i);
|
||||
for (uptr i = r3_beg; i < r3_end; i++)
|
||||
if (!AddressIsPoisoned(i))
|
||||
return 0;
|
||||
return 1;
|
||||
return reinterpret_cast<const void *>(i);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int __sanitizer_verify_contiguous_container(const void *beg_p,
|
||||
const void *mid_p,
|
||||
const void *end_p) {
|
||||
return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p,
|
||||
end_p) == nullptr;
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
|
@ -620,41 +620,57 @@ void DescribeThread(AsanThreadContext *context) {
|
||||
// immediately after printing error report.
|
||||
class ScopedInErrorReport {
|
||||
public:
|
||||
explicit ScopedInErrorReport(ReportData *report = nullptr) {
|
||||
static atomic_uint32_t num_calls;
|
||||
static u32 reporting_thread_tid;
|
||||
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
|
||||
explicit ScopedInErrorReport(ReportData *report = nullptr,
|
||||
bool fatal = false) {
|
||||
halt_on_error_ = fatal || flags()->halt_on_error;
|
||||
|
||||
if (lock_.TryLock()) {
|
||||
StartReporting(report);
|
||||
return;
|
||||
}
|
||||
|
||||
// ASan found two bugs in different threads simultaneously.
|
||||
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
if (reporting_thread_tid_ == current_tid ||
|
||||
reporting_thread_tid_ == kInvalidTid) {
|
||||
// This is either asynch signal or nested error during error reporting.
|
||||
// Fail simple to avoid deadlocks in Report().
|
||||
|
||||
// Can't use Report() here because of potential deadlocks
|
||||
// in nested signal handlers.
|
||||
const char msg[] = "AddressSanitizer: nested bug in the same thread, "
|
||||
"aborting.\n";
|
||||
WriteToFile(kStderrFd, msg, sizeof(msg));
|
||||
|
||||
internal__exit(common_flags()->exitcode);
|
||||
}
|
||||
|
||||
if (halt_on_error_) {
|
||||
// Do not print more than one report, otherwise they will mix up.
|
||||
// Error reporting functions shouldn't return at this situation, as
|
||||
// they are defined as no-return.
|
||||
// they are effectively no-returns.
|
||||
|
||||
Report("AddressSanitizer: while reporting a bug found another one. "
|
||||
"Ignoring.\n");
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
if (current_tid != reporting_thread_tid) {
|
||||
// ASan found two bugs in different threads simultaneously. Sleep
|
||||
// long enough to make sure that the thread which started to print
|
||||
// an error report will finish doing it.
|
||||
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
||||
}
|
||||
"Ignoring.\n");
|
||||
|
||||
// Sleep long enough to make sure that the thread which started
|
||||
// to print an error report will finish doing it.
|
||||
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
||||
|
||||
// If we're still not dead for some reason, use raw _exit() instead of
|
||||
// Die() to bypass any additional checks.
|
||||
internal__exit(common_flags()->exitcode);
|
||||
} else {
|
||||
// The other thread will eventually finish reporting
|
||||
// so it's safe to wait
|
||||
lock_.Lock();
|
||||
}
|
||||
if (report) report_data = *report;
|
||||
report_happened = true;
|
||||
ASAN_ON_ERROR();
|
||||
// Make sure the registry and sanitizer report mutexes are locked while
|
||||
// we're printing an error report.
|
||||
// We can lock them only here to avoid self-deadlock in case of
|
||||
// recursive reports.
|
||||
asanThreadRegistry().Lock();
|
||||
CommonSanitizerReportMutex.Lock();
|
||||
reporting_thread_tid = GetCurrentTidOrInvalid();
|
||||
Printf("===================================================="
|
||||
"=============\n");
|
||||
|
||||
StartReporting(report);
|
||||
}
|
||||
// Destructor is NORETURN, as functions that report errors are.
|
||||
NORETURN ~ScopedInErrorReport() {
|
||||
|
||||
~ScopedInErrorReport() {
|
||||
// Make sure the current thread is announced.
|
||||
DescribeThread(GetCurrentThread());
|
||||
// We may want to grab this lock again when printing stats.
|
||||
@ -665,11 +681,39 @@ class ScopedInErrorReport {
|
||||
if (error_report_callback) {
|
||||
error_report_callback(error_message_buffer);
|
||||
}
|
||||
Report("ABORTING\n");
|
||||
Die();
|
||||
CommonSanitizerReportMutex.Unlock();
|
||||
reporting_thread_tid_ = kInvalidTid;
|
||||
lock_.Unlock();
|
||||
if (halt_on_error_) {
|
||||
Report("ABORTING\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void StartReporting(ReportData *report) {
|
||||
if (report) report_data = *report;
|
||||
report_happened = true;
|
||||
ASAN_ON_ERROR();
|
||||
// Make sure the registry and sanitizer report mutexes are locked while
|
||||
// we're printing an error report.
|
||||
// We can lock them only here to avoid self-deadlock in case of
|
||||
// recursive reports.
|
||||
asanThreadRegistry().Lock();
|
||||
CommonSanitizerReportMutex.Lock();
|
||||
reporting_thread_tid_ = GetCurrentTidOrInvalid();
|
||||
Printf("===================================================="
|
||||
"=============\n");
|
||||
}
|
||||
|
||||
static StaticSpinMutex lock_;
|
||||
static u32 reporting_thread_tid_;
|
||||
bool halt_on_error_;
|
||||
};
|
||||
|
||||
StaticSpinMutex ScopedInErrorReport::lock_;
|
||||
u32 ScopedInErrorReport::reporting_thread_tid_;
|
||||
|
||||
void ReportStackOverflow(const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report;
|
||||
Decorator d;
|
||||
@ -686,7 +730,7 @@ void ReportStackOverflow(const SignalContext &sig) {
|
||||
}
|
||||
|
||||
void ReportDeadlySignal(const char *description, const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report;
|
||||
ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
@ -743,7 +787,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
ReportErrorSummary("new-delete-type-mismatch", &stack);
|
||||
Report("HINT: if you don't care about these warnings you may set "
|
||||
Report("HINT: if you don't care about these errors you may set "
|
||||
"ASAN_OPTIONS=new_delete_type_mismatch=0\n");
|
||||
}
|
||||
|
||||
@ -783,7 +827,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
ReportErrorSummary("alloc-dealloc-mismatch", &stack);
|
||||
Report("HINT: if you don't care about these warnings you may set "
|
||||
Report("HINT: if you don't care about these errors you may set "
|
||||
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
|
||||
}
|
||||
|
||||
@ -885,7 +929,7 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
|
||||
Printf(" [2]:\n");
|
||||
StackDepotGet(stack_id2).Print();
|
||||
}
|
||||
Report("HINT: if you don't care about these warnings you may set "
|
||||
Report("HINT: if you don't care about these errors you may set "
|
||||
"ASAN_OPTIONS=detect_odr_violation=0\n");
|
||||
InternalScopedString error_msg(256);
|
||||
error_msg.append("odr-violation: global '%s' at %s",
|
||||
@ -957,13 +1001,8 @@ void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// --------------------------- Interface --------------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
|
||||
uptr access_size, u32 exp) {
|
||||
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
uptr access_size, u32 exp, bool fatal) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
|
||||
// Optimization experiments.
|
||||
@ -1032,7 +1071,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
|
||||
|
||||
ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
|
||||
bug_descr };
|
||||
ScopedInErrorReport in_report(&report);
|
||||
ScopedInErrorReport in_report(&report, fatal);
|
||||
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
@ -1058,6 +1097,18 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
|
||||
PrintShadowMemoryForAddress(addr);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// --------------------------- Interface --------------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
|
||||
uptr access_size, u32 exp) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
bool fatal = flags()->halt_on_error;
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
|
||||
}
|
||||
|
||||
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
|
||||
error_report_callback = callback;
|
||||
if (callback) {
|
||||
|
@ -47,45 +47,41 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size);
|
||||
void DescribeThread(AsanThreadContext *context);
|
||||
|
||||
// Different kinds of error reports.
|
||||
void NORETURN ReportStackOverflow(const SignalContext &sig);
|
||||
void NORETURN ReportDeadlySignal(const char* description,
|
||||
const SignalContext &sig);
|
||||
void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
||||
AllocType alloc_type,
|
||||
AllocType dealloc_type);
|
||||
void NORETURN
|
||||
ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
||||
uptr old_mid, uptr new_mid,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
uptr access_size, u32 exp, bool fatal);
|
||||
void ReportStackOverflow(const SignalContext &sig);
|
||||
void ReportDeadlySignal(const char *description, const SignalContext &sig);
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
BufferedStackTrace *free_stack);
|
||||
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
|
||||
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
|
||||
void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
||||
AllocType alloc_type,
|
||||
AllocType dealloc_type);
|
||||
void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
|
||||
void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
||||
uptr old_mid, uptr new_mid,
|
||||
BufferedStackTrace *stack);
|
||||
|
||||
void NORETURN
|
||||
ReportODRViolation(const __asan_global *g1, u32 stack_id1,
|
||||
const __asan_global *g2, u32 stack_id2);
|
||||
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
|
||||
const __asan_global *g2, u32 stack_id2);
|
||||
|
||||
// Mac-specific errors and warnings.
|
||||
void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -111,13 +111,18 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## size(uptr addr) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
|
||||
}
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## size ## _noabort(uptr addr) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
|
||||
} \
|
||||
|
||||
ASAN_REPORT_ERROR(load, false, 1)
|
||||
ASAN_REPORT_ERROR(load, false, 2)
|
||||
@ -130,22 +135,27 @@ ASAN_REPORT_ERROR(store, true, 4)
|
||||
ASAN_REPORT_ERROR(store, true, 8)
|
||||
ASAN_REPORT_ERROR(store, true, 16)
|
||||
|
||||
#define ASAN_REPORT_ERROR_N(type, is_write) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
#define ASAN_REPORT_ERROR_N(type, is_write) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
|
||||
}
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
|
||||
} \
|
||||
|
||||
ASAN_REPORT_ERROR_N(load, false)
|
||||
ASAN_REPORT_ERROR_N(store, true)
|
||||
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \
|
||||
uptr sp = MEM_TO_SHADOW(addr); \
|
||||
uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
|
||||
: *reinterpret_cast<u16 *>(sp); \
|
||||
@ -157,7 +167,8 @@ ASAN_REPORT_ERROR_N(store, true)
|
||||
*__asan_test_only_reported_buggy_pointer = addr; \
|
||||
} else { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \
|
||||
fatal); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
@ -165,12 +176,16 @@ ASAN_REPORT_ERROR_N(store, true)
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_##type##size(uptr addr) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_exp_##type##size(uptr addr, u32 exp) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \
|
||||
}
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_##type##size ## _noabort(uptr addr) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \
|
||||
} \
|
||||
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
|
||||
@ -188,7 +203,7 @@ NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_loadN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, false, size, 0);
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +212,16 @@ NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_exp_loadN(uptr addr, uptr size, u32 exp) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, false, size, exp);
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, exp, true);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_loadN_noabort(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,7 +230,7 @@ NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_storeN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, true, size, 0);
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +239,16 @@ NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_exp_storeN(uptr addr, uptr size, u32 exp) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, true, size, exp);
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, exp, true);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_storeN_noabort(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,6 +324,8 @@ static void InitializeHighMemEnd() {
|
||||
}
|
||||
|
||||
static void ProtectGap(uptr addr, uptr size) {
|
||||
if (!flags()->protect_shadow_gap)
|
||||
return;
|
||||
void *res = MmapNoAccess(addr, size, "shadow gap");
|
||||
if (addr == (uptr)res)
|
||||
return;
|
||||
@ -376,8 +411,6 @@ static void AsanInitInternal() {
|
||||
// initialization steps look at flags().
|
||||
InitializeFlags();
|
||||
|
||||
CheckVMASize();
|
||||
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanCheckDynamicRTPrereqs();
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -255,6 +255,9 @@ INTERFACE_FUNCTION(__asan_memcpy);
|
||||
INTERFACE_FUNCTION(__asan_memset);
|
||||
INTERFACE_FUNCTION(__asan_memmove);
|
||||
|
||||
INTERFACE_FUNCTION(__asan_alloca_poison);
|
||||
INTERFACE_FUNCTION(__asan_allocas_unpoison);
|
||||
|
||||
INTERFACE_FUNCTION(__asan_register_globals)
|
||||
INTERFACE_FUNCTION(__asan_unregister_globals)
|
||||
|
||||
@ -298,6 +301,7 @@ INTERFACE_FUNCTION(__asan_stack_free_10)
|
||||
|
||||
// FIXME: we might want to have a sanitizer_win_dll_thunk?
|
||||
INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
|
||||
INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_dump)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
|
||||
@ -315,6 +319,7 @@ INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_heap_size)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_ownership)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
|
||||
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
|
||||
|
@ -22,6 +22,7 @@
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// First, declare CRT sections we'll be using in this file
|
||||
|
@ -37,6 +37,8 @@ case "${target}" in
|
||||
aarch64*-*-linux*)
|
||||
if test x$ac_cv_sizeof_void_p = x8; then
|
||||
TSAN_SUPPORTED=yes
|
||||
LSAN_SUPPORTED=yes
|
||||
TSAN_TARGET_DEPENDENT_OBJECTS=tsan_rtl_aarch64.lo
|
||||
fi
|
||||
;;
|
||||
x86_64-*-darwin[1]* | i?86-*-darwin[1]*)
|
||||
|
@ -103,6 +103,12 @@ extern "C" {
|
||||
int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
|
||||
const void *end);
|
||||
|
||||
// Similar to __sanitizer_verify_contiguous_container but returns the address
|
||||
// of the first improperly poisoned byte otherwise. Returns null if the area
|
||||
// is poisoned properly.
|
||||
const void *__sanitizer_contiguous_container_find_bad_address(
|
||||
const void *beg, const void *mid, const void *end);
|
||||
|
||||
// Print the stack trace leading to this call. Useful for debugging user code.
|
||||
void __sanitizer_print_stack_trace();
|
||||
|
||||
|
@ -25,9 +25,11 @@ extern "C" {
|
||||
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
|
||||
// This is intended for use by sandboxing code.
|
||||
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
|
||||
// Get the number of total unique covered entities (blocks, edges, calls).
|
||||
// Get the number of unique covered blocks (or edges).
|
||||
// This can be useful for coverage-directed in-process fuzzers.
|
||||
uintptr_t __sanitizer_get_total_unique_coverage();
|
||||
// Get the number of unique indirect caller-callee pairs.
|
||||
uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
|
||||
|
||||
// Reset the basic-block (edge) coverage to the initial state.
|
||||
// Useful for in-process fuzzing to start collecting coverage from scratch.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "interception.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
namespace __interception {
|
||||
|
@ -30,7 +30,7 @@ struct ChunkMetadata {
|
||||
u32 stack_trace_id;
|
||||
};
|
||||
|
||||
#if defined(__mips64)
|
||||
#if defined(__mips64) || defined(__aarch64__)
|
||||
static const uptr kMaxAllowedMallocSize = 4UL << 30;
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
|
@ -117,6 +117,10 @@ static inline bool CanBeAHeapPointer(uptr p) {
|
||||
return ((p >> 47) == 0);
|
||||
#elif defined(__mips64)
|
||||
return ((p >> 40) == 0);
|
||||
#elif defined(__aarch64__)
|
||||
unsigned runtimeVMA =
|
||||
(MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
|
||||
return ((p >> runtimeVMA) == 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
@ -20,8 +20,8 @@
|
||||
#include "sanitizer_common/sanitizer_stoptheworld.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
|
||||
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips64)) \
|
||||
&& (SANITIZER_WORDSIZE == 64)
|
||||
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
|
||||
&& (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
|
||||
#define CAN_SANITIZE_LEAKS 1
|
||||
#else
|
||||
#define CAN_SANITIZE_LEAKS 0
|
||||
|
@ -21,8 +21,11 @@
|
||||
# define CFI_STARTPROC .cfi_startproc
|
||||
# define CFI_ENDPROC .cfi_endproc
|
||||
# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
|
||||
# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n
|
||||
# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
|
||||
# define CFI_OFFSET(reg, n) .cfi_offset reg, n
|
||||
# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
|
||||
# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n
|
||||
# define CFI_RESTORE(reg) .cfi_restore reg
|
||||
|
||||
#else // No CFI
|
||||
@ -30,7 +33,10 @@
|
||||
# define CFI_STARTPROC
|
||||
# define CFI_ENDPROC
|
||||
# define CFI_ADJUST_CFA_OFFSET(n)
|
||||
# define CFI_DEF_CFA_OFFSET(n)
|
||||
# define CFI_REL_OFFSET(reg, n)
|
||||
# define CFI_OFFSET(reg, n)
|
||||
# define CFI_DEF_CFA_REGISTER(reg)
|
||||
# define CFI_DEF_CFA(reg, n)
|
||||
# define CFI_RESTORE(reg)
|
||||
#endif
|
||||
|
@ -162,7 +162,7 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
||||
}
|
||||
|
||||
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
||||
error_t err) {
|
||||
const char *mmap_type, error_t err) {
|
||||
static int recursion_count;
|
||||
if (recursion_count) {
|
||||
// The Report() and CHECK calls below may call mmap recursively and fail.
|
||||
@ -172,9 +172,11 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
||||
}
|
||||
recursion_count++;
|
||||
Report("ERROR: %s failed to "
|
||||
"allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
|
||||
SanitizerToolName, size, size, mem_type, err);
|
||||
"%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
|
||||
SanitizerToolName, mmap_type, size, size, mem_type, err);
|
||||
#ifndef SANITIZER_GO
|
||||
DumpProcessMap();
|
||||
#endif
|
||||
UNREACHABLE("unable to mmap");
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void NORETURN Die();
|
||||
void NORETURN
|
||||
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
|
||||
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
|
||||
error_t err);
|
||||
const char *mmap_type, error_t err);
|
||||
|
||||
// Set the name of the current thread to 'name', return true on succees.
|
||||
// The name may be truncated to a system-dependent limit.
|
||||
|
@ -439,6 +439,8 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
|
||||
#if SANITIZER_INTERCEPT_MEMCHR
|
||||
INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
|
||||
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
|
||||
return internal_memchr(s, c, n);
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
|
||||
void *res = REAL(memchr)(s, c, n);
|
||||
@ -2444,6 +2446,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
|
||||
INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
|
||||
__sanitizer_iovec local_iovec;
|
||||
|
||||
if (data) {
|
||||
if (request == ptrace_setregs)
|
||||
@ -2452,11 +2455,19 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
|
||||
else if (request == ptrace_setfpxregs)
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
|
||||
else if (request == ptrace_setvfpregs)
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
|
||||
else if (request == ptrace_setsiginfo)
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
|
||||
else if (request == ptrace_setregset) {
|
||||
__sanitizer_iovec *iov = (__sanitizer_iovec *)data;
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len);
|
||||
// Some kernel might zero the iovec::iov_base in case of invalid
|
||||
// write access. In this case copy the invalid address for further
|
||||
// inspection.
|
||||
else if (request == ptrace_setregset || request == ptrace_getregset) {
|
||||
__sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec));
|
||||
local_iovec = *iovec;
|
||||
if (request == ptrace_setregset)
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2474,13 +2485,17 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
|
||||
else if (request == ptrace_getfpxregs)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
|
||||
else if (request == ptrace_getvfpregs)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
|
||||
else if (request == ptrace_getsiginfo)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
|
||||
else if (request == ptrace_geteventmsg)
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
|
||||
else if (request == ptrace_getregset) {
|
||||
__sanitizer_iovec *iov = (__sanitizer_iovec *)data;
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len);
|
||||
__sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec));
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base,
|
||||
local_iovec.iov_len);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@ -4874,9 +4889,8 @@ static void initialize_obstack(__sanitizer_obstack *obstack) {
|
||||
sizeof(*obstack->chunk));
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack,
|
||||
_OBSTACK_SIZE_T sz, _OBSTACK_SIZE_T align,
|
||||
void *(*alloc_fn)(uptr arg, SIZE_T sz),
|
||||
INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz,
|
||||
int align, void *(*alloc_fn)(uptr arg, uptr sz),
|
||||
void (*free_fn)(uptr arg, void *p)) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn,
|
||||
@ -4885,10 +4899,8 @@ INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack,
|
||||
if (res) initialize_obstack(obstack);
|
||||
return res;
|
||||
}
|
||||
INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack,
|
||||
_OBSTACK_SIZE_T sz, _OBSTACK_SIZE_T align,
|
||||
void *(*alloc_fn)(SIZE_T sz),
|
||||
void (*free_fn)(void *p)) {
|
||||
INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz,
|
||||
int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn,
|
||||
free_fn);
|
||||
@ -4896,8 +4908,7 @@ INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack,
|
||||
if (res) initialize_obstack(obstack);
|
||||
return res;
|
||||
}
|
||||
INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack,
|
||||
_OBSTACK_SIZE_T length) {
|
||||
INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length);
|
||||
REAL(_obstack_newchunk)(obstack, length);
|
||||
@ -5238,6 +5249,39 @@ INTERCEPTOR(int, mincore, void *addr, uptr length, unsigned char *vec) {
|
||||
#define INIT_MINCORE
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_PROCESS_VM_READV
|
||||
INTERCEPTOR(SSIZE_T, process_vm_readv, int pid, __sanitizer_iovec *local_iov,
|
||||
uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt,
|
||||
uptr flags) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, process_vm_readv, pid, local_iov, liovcnt,
|
||||
remote_iov, riovcnt, flags);
|
||||
SSIZE_T res = REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov,
|
||||
riovcnt, flags);
|
||||
if (res > 0)
|
||||
write_iovec(ctx, local_iov, liovcnt, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov,
|
||||
uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt,
|
||||
uptr flags) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, process_vm_writev, pid, local_iov, liovcnt,
|
||||
remote_iov, riovcnt, flags);
|
||||
SSIZE_T res = REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov,
|
||||
riovcnt, flags);
|
||||
if (res > 0)
|
||||
read_iovec(ctx, local_iov, liovcnt, res);
|
||||
return res;
|
||||
}
|
||||
#define INIT_PROCESS_VM_READV \
|
||||
COMMON_INTERCEPT_FUNCTION(process_vm_readv); \
|
||||
COMMON_INTERCEPT_FUNCTION(process_vm_writev);
|
||||
#else
|
||||
#define INIT_PROCESS_VM_READV
|
||||
#endif
|
||||
|
||||
static void InitializeCommonInterceptors() {
|
||||
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
|
||||
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
|
||||
@ -5411,4 +5455,5 @@ static void InitializeCommonInterceptors() {
|
||||
INIT_SEM;
|
||||
INIT_PTHREAD_SETCANCEL;
|
||||
INIT_MINCORE;
|
||||
INIT_PROCESS_VM_READV;
|
||||
}
|
||||
|
@ -51,6 +51,12 @@ static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
|
||||
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
|
||||
|
||||
static atomic_uintptr_t coverage_counter;
|
||||
static atomic_uintptr_t caller_callee_counter;
|
||||
|
||||
static void ResetGlobalCounters() {
|
||||
return atomic_store(&coverage_counter, 0, memory_order_relaxed);
|
||||
return atomic_store(&caller_callee_counter, 0, memory_order_relaxed);
|
||||
}
|
||||
|
||||
// pc_array is the array containing the covered PCs.
|
||||
// To make the pc_array thread- and async-signal-safe it has to be large enough.
|
||||
@ -223,7 +229,8 @@ void CoverageData::InitializeGuardArray(s32 *guards) {
|
||||
Enable(); // Make sure coverage is enabled at this point.
|
||||
s32 n = guards[0];
|
||||
for (s32 j = 1; j <= n; j++) {
|
||||
uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
|
||||
uptr idx = atomic_load_relaxed(&pc_array_index);
|
||||
atomic_store_relaxed(&pc_array_index, idx + 1);
|
||||
guards[j] = -static_cast<s32>(idx + 1);
|
||||
}
|
||||
}
|
||||
@ -433,7 +440,7 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
|
||||
uptr was = 0;
|
||||
if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
|
||||
memory_order_seq_cst)) {
|
||||
atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
|
||||
atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
if (was == callee) // Already have this callee.
|
||||
@ -905,6 +912,11 @@ uptr __sanitizer_get_total_unique_coverage() {
|
||||
return atomic_load(&coverage_counter, memory_order_relaxed);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __sanitizer_get_total_unique_caller_callee_pairs() {
|
||||
return atomic_load(&caller_callee_counter, memory_order_relaxed);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_cov_trace_func_enter(s32 *id) {
|
||||
coverage_data.TraceBasicBlock(id);
|
||||
@ -915,6 +927,7 @@ void __sanitizer_cov_trace_basic_block(s32 *id) {
|
||||
}
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_reset_coverage() {
|
||||
ResetGlobalCounters();
|
||||
coverage_data.ReinitializeGuards();
|
||||
internal_bzero_aligned16(
|
||||
coverage_data.data(),
|
||||
|
@ -51,6 +51,9 @@ extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
|
||||
const void *end);
|
||||
} // extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const void *__sanitizer_contiguous_container_find_bad_address(
|
||||
const void *beg, const void *mid, const void *end);
|
||||
} // extern "C"
|
||||
|
||||
#endif // SANITIZER_INTERFACE_INTERNAL_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "sanitizer_platform.h"
|
||||
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
|
||||
|
||||
#include "sanitizer_libignore.h"
|
||||
#include "sanitizer_flags.h"
|
||||
|
@ -495,7 +495,7 @@ void BlockingMutex::CheckLocked() {
|
||||
// Note that getdents64 uses a different structure format. We only provide the
|
||||
// 32-bit syscall here.
|
||||
struct linux_dirent {
|
||||
#if SANITIZER_X32
|
||||
#if SANITIZER_X32 || defined(__aarch64__)
|
||||
u64 d_ino;
|
||||
u64 d_off;
|
||||
#else
|
||||
@ -503,6 +503,9 @@ struct linux_dirent {
|
||||
unsigned long d_off;
|
||||
#endif
|
||||
unsigned short d_reclen;
|
||||
#ifdef __aarch64__
|
||||
unsigned char d_type;
|
||||
#endif
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
|
@ -60,20 +60,6 @@
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// This function is defined elsewhere if we intercepted pthread_attr_getstack.
|
||||
extern "C" {
|
||||
SANITIZER_WEAK_ATTRIBUTE int
|
||||
real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
|
||||
} // extern "C"
|
||||
|
||||
static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
|
||||
#if !SANITIZER_GO
|
||||
if (&real_pthread_attr_getstack)
|
||||
return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
|
||||
#endif
|
||||
return pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE int
|
||||
real_sigaction(int signum, const void *act, void *oldact);
|
||||
|
||||
@ -126,7 +112,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
|
||||
uptr stacksize = 0;
|
||||
void *stackaddr = nullptr;
|
||||
my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
|
||||
my_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
|
||||
@ -178,11 +164,15 @@ static uptr g_tls_size;
|
||||
# define DL_INTERNAL_FUNCTION
|
||||
#endif
|
||||
|
||||
#if defined(__mips__)
|
||||
#if defined(__mips__) || defined(__powerpc64__)
|
||||
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
|
||||
// head structure. It lies before the static tls blocks.
|
||||
static uptr TlsPreTcbSize() {
|
||||
const uptr kTcbHead = 16;
|
||||
# if defined(__mips__)
|
||||
const uptr kTcbHead = 16; // sizeof (tcbhead_t)
|
||||
# elif defined(__powerpc64__)
|
||||
const uptr kTcbHead = 88; // sizeof (tcbhead_t)
|
||||
# endif
|
||||
const uptr kTlsAlign = 16;
|
||||
const uptr kTlsPreTcbSize =
|
||||
(ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
|
||||
@ -213,9 +203,9 @@ void InitTlsSize() {
|
||||
}
|
||||
|
||||
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
|
||||
|| defined(__aarch64__)) \
|
||||
|| defined(__aarch64__) || defined(__powerpc64__)) \
|
||||
&& SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
// sizeof(struct thread) from glibc.
|
||||
// sizeof(struct pthread) from glibc.
|
||||
static atomic_uintptr_t kThreadDescriptorSize;
|
||||
|
||||
uptr ThreadDescriptorSize() {
|
||||
@ -230,7 +220,7 @@ uptr ThreadDescriptorSize() {
|
||||
char *end;
|
||||
int minor = internal_simple_strtoll(buf + 8, &end, 10);
|
||||
if (end != buf + 8 && (*end == '\0' || *end == '.')) {
|
||||
/* sizeof(struct thread) values from various glibc versions. */
|
||||
/* sizeof(struct pthread) values from various glibc versions. */
|
||||
if (SANITIZER_X32)
|
||||
val = 1728; // Assume only one particular version for x32.
|
||||
else if (minor <= 3)
|
||||
@ -266,6 +256,10 @@ uptr ThreadDescriptorSize() {
|
||||
val = 1776;
|
||||
atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
|
||||
return val;
|
||||
#elif defined(__powerpc64__)
|
||||
val = 1776; // from glibc.ppc64le 2.20-8.fc21
|
||||
atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
|
||||
return val;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -297,6 +291,15 @@ uptr ThreadSelf() {
|
||||
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
|
||||
# elif defined(__aarch64__)
|
||||
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
|
||||
# elif defined(__powerpc64__)
|
||||
// PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
|
||||
// points to the end of the TCB + 0x7000. The pthread_descr structure is
|
||||
// immediately in front of the TCB. TlsPreTcbSize() includes the size of the
|
||||
// TCB and the size of pthread_descr.
|
||||
const uptr kTlsTcbOffset = 0x7000;
|
||||
uptr thread_pointer;
|
||||
asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
|
||||
descr_addr = thread_pointer - TlsPreTcbSize();
|
||||
# else
|
||||
# error "unsupported CPU arch"
|
||||
# endif
|
||||
@ -332,7 +335,7 @@ static void GetTls(uptr *addr, uptr *size) {
|
||||
*size = GetTlsSize();
|
||||
*addr -= *size;
|
||||
*addr += ThreadDescriptorSize();
|
||||
# elif defined(__mips__) || defined(__aarch64__)
|
||||
# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
*addr = ThreadSelf();
|
||||
*size = GetTlsSize();
|
||||
# else
|
||||
@ -398,33 +401,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SANITIZER_GO
|
||||
void AdjustStackSize(void *attr_) {
|
||||
pthread_attr_t *attr = (pthread_attr_t *)attr_;
|
||||
uptr stackaddr = 0;
|
||||
size_t stacksize = 0;
|
||||
my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
|
||||
// GLibC will return (0 - stacksize) as the stack address in the case when
|
||||
// stacksize is set, but stackaddr is not.
|
||||
bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
|
||||
// We place a lot of tool data into TLS, account for that.
|
||||
const uptr minstacksize = GetTlsSize() + 128*1024;
|
||||
if (stacksize < minstacksize) {
|
||||
if (!stack_set) {
|
||||
if (stacksize != 0) {
|
||||
VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
|
||||
minstacksize);
|
||||
pthread_attr_setstacksize(attr, minstacksize);
|
||||
}
|
||||
} else {
|
||||
Printf("Sanitizer: pre-allocated stack size is insufficient: "
|
||||
"%zu < %zu\n", stacksize, minstacksize);
|
||||
Printf("Sanitizer: pthread_create is likely to fail.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !SANITIZER_GO
|
||||
|
||||
# if !SANITIZER_FREEBSD
|
||||
typedef ElfW(Phdr) Elf_Phdr;
|
||||
# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
|
||||
|
@ -39,6 +39,7 @@ extern char **environ;
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/vm_statistics.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
@ -57,6 +58,7 @@ namespace __sanitizer {
|
||||
// ---------------------- sanitizer_libc.h
|
||||
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
|
||||
return (uptr)mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
@ -367,8 +369,18 @@ uptr GetRSS() {
|
||||
return info.resident_size;
|
||||
}
|
||||
|
||||
void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
|
||||
void internal_join_thread(void *th) { }
|
||||
void *internal_start_thread(void(*func)(void *arg), void *arg) {
|
||||
// Start the thread with signals blocked, otherwise it can steal user signals.
|
||||
__sanitizer_sigset_t set, old;
|
||||
internal_sigfillset(&set);
|
||||
internal_sigprocmask(SIG_SETMASK, &set, &old);
|
||||
pthread_t th;
|
||||
pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
|
||||
internal_sigprocmask(SIG_SETMASK, &old, 0);
|
||||
return th;
|
||||
}
|
||||
|
||||
void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
|
337
libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
Normal file
337
libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
Normal file
@ -0,0 +1,337 @@
|
||||
//===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains Mac-specific malloc interceptors and a custom zone
|
||||
// implementation, which together replace the system allocator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if !SANITIZER_MAC
|
||||
#error "This file should only be compiled on Darwin."
|
||||
#endif
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <dlfcn.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_mac.h"
|
||||
|
||||
// Similar code is used in Google Perftools,
|
||||
// http://code.google.com/p/google-perftools.
|
||||
|
||||
static malloc_zone_t sanitizer_zone;
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
|
||||
vm_size_t start_size, unsigned zone_flags) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
|
||||
COMMON_MALLOC_MEMALIGN(page_size, allocated_size);
|
||||
malloc_zone_t *new_zone = (malloc_zone_t *)p;
|
||||
internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
|
||||
new_zone->zone_name = NULL; // The name will be changed anyway.
|
||||
if (GetMacosVersion() >= MACOS_VERSION_LION) {
|
||||
// Prevent the client app from overwriting the zone contents.
|
||||
// Library functions that need to modify the zone will set PROT_WRITE on it.
|
||||
// This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
|
||||
mprotect(new_zone, allocated_size, PROT_READ);
|
||||
}
|
||||
return new_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
return &sanitizer_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
|
||||
// FIXME: ASan should support purgeable allocations.
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=139
|
||||
COMMON_MALLOC_ENTER();
|
||||
return &sanitizer_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
COMMON_MALLOC_ENTER();
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
COMMON_MALLOC_ENTER();
|
||||
// Must return 0 if the contents were not purged since the last call to
|
||||
// malloc_make_purgeable().
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
// Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
|
||||
// bytes.
|
||||
size_t buflen =
|
||||
sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
|
||||
InternalScopedString new_name(buflen);
|
||||
if (name && zone->introspect == sanitizer_zone.introspect) {
|
||||
new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
|
||||
name = new_name.data();
|
||||
}
|
||||
|
||||
// Call the system malloc's implementation for both external and our zones,
|
||||
// since that appropriately changes VM region protections on the zone.
|
||||
REAL(malloc_set_zone_name)(zone, name);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, malloc, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_MALLOC(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
if (!ptr) return;
|
||||
COMMON_MALLOC_FREE(ptr);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_REALLOC(ptr, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_CALLOC(nmemb, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, valloc, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_VALLOC(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
return sanitizer_zone.introspect->good_size(&sanitizer_zone, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
CHECK(memptr);
|
||||
COMMON_MALLOC_MEMALIGN(alignment, size);
|
||||
if (p) {
|
||||
*memptr = p;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(glider): the __sanitizer_mz_* functions should be united with the Linux
|
||||
// wrappers, as they are basically copied from there.
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) {
|
||||
COMMON_MALLOC_SIZE(ptr);
|
||||
return size;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_MALLOC(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
|
||||
if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const size_t kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static size_t allocated;
|
||||
size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
allocated += size_in_words;
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
COMMON_MALLOC_CALLOC(nmemb, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_VALLOC(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
#define GET_ZONE_FOR_PTR(ptr) \
|
||||
malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
|
||||
const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
|
||||
|
||||
void ALWAYS_INLINE free_common(void *context, void *ptr) {
|
||||
if (!ptr) return;
|
||||
// FIXME: need to retire this flag.
|
||||
if (!COMMON_MALLOC_IGNORE_INVALID_FREE) {
|
||||
COMMON_MALLOC_FREE(ptr);
|
||||
} else {
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(glider): the allocation callbacks need to be refactored.
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
|
||||
free_common(zone, ptr);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) {
|
||||
if (!ptr) {
|
||||
COMMON_MALLOC_MALLOC(new_size);
|
||||
return p;
|
||||
} else {
|
||||
COMMON_MALLOC_SIZE(ptr);
|
||||
if (size) {
|
||||
COMMON_MALLOC_REALLOC(ptr, new_size);
|
||||
return p;
|
||||
} else {
|
||||
// We can't recover from reallocating an unknown address, because
|
||||
// this would require reading at most |new_size| bytes from
|
||||
// potentially unaccessible memory.
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_mz_destroy(malloc_zone_t* zone) {
|
||||
// A no-op -- we will not be destroyed!
|
||||
Report("__sanitizer_mz_destroy() called -- ignoring\n");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
|
||||
COMMON_MALLOC_ENTER();
|
||||
COMMON_MALLOC_MEMALIGN(align, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
// This function is currently unused, and we build with -Werror.
|
||||
#if 0
|
||||
void __sanitizer_mz_free_definite_size(
|
||||
malloc_zone_t* zone, void *ptr, size_t size) {
|
||||
// TODO(glider): check that |size| is valid.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
#endif
|
||||
|
||||
kern_return_t mi_enumerator(task_t task, void *,
|
||||
unsigned type_mask, vm_address_t zone_address,
|
||||
memory_reader_t reader,
|
||||
vm_range_recorder_t recorder) {
|
||||
// Should enumerate all the pointers we have. Seems like a lot of work.
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
size_t mi_good_size(malloc_zone_t *zone, size_t size) {
|
||||
// I think it's always safe to return size, but we maybe could do better.
|
||||
return size;
|
||||
}
|
||||
|
||||
boolean_t mi_check(malloc_zone_t *zone) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void mi_print(malloc_zone_t *zone, boolean_t verbose) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void mi_log(malloc_zone_t *zone, void *address) {
|
||||
// I don't think we support anything like this
|
||||
}
|
||||
|
||||
void mi_force_lock(malloc_zone_t *zone) {
|
||||
COMMON_MALLOC_FORCE_LOCK();
|
||||
}
|
||||
|
||||
void mi_force_unlock(malloc_zone_t *zone) {
|
||||
COMMON_MALLOC_FORCE_UNLOCK();
|
||||
}
|
||||
|
||||
void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
|
||||
COMMON_MALLOC_FILL_STATS(zone, stats);
|
||||
}
|
||||
|
||||
boolean_t mi_zone_locked(malloc_zone_t *zone) {
|
||||
// UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace COMMON_MALLOC_NAMESPACE {
|
||||
|
||||
void ReplaceSystemMalloc() {
|
||||
static malloc_introspection_t sanitizer_zone_introspection;
|
||||
// Ok to use internal_memset, these places are not performance-critical.
|
||||
internal_memset(&sanitizer_zone_introspection, 0,
|
||||
sizeof(sanitizer_zone_introspection));
|
||||
|
||||
sanitizer_zone_introspection.enumerator = &mi_enumerator;
|
||||
sanitizer_zone_introspection.good_size = &mi_good_size;
|
||||
sanitizer_zone_introspection.check = &mi_check;
|
||||
sanitizer_zone_introspection.print = &mi_print;
|
||||
sanitizer_zone_introspection.log = &mi_log;
|
||||
sanitizer_zone_introspection.force_lock = &mi_force_lock;
|
||||
sanitizer_zone_introspection.force_unlock = &mi_force_unlock;
|
||||
sanitizer_zone_introspection.statistics = &mi_statistics;
|
||||
sanitizer_zone_introspection.zone_locked = &mi_zone_locked;
|
||||
|
||||
internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t));
|
||||
|
||||
// Use version 6 for OSX >= 10.6.
|
||||
sanitizer_zone.version = 6;
|
||||
sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME;
|
||||
sanitizer_zone.size = &__sanitizer_mz_size;
|
||||
sanitizer_zone.malloc = &__sanitizer_mz_malloc;
|
||||
sanitizer_zone.calloc = &__sanitizer_mz_calloc;
|
||||
sanitizer_zone.valloc = &__sanitizer_mz_valloc;
|
||||
sanitizer_zone.free = &__sanitizer_mz_free;
|
||||
sanitizer_zone.realloc = &__sanitizer_mz_realloc;
|
||||
sanitizer_zone.destroy = &__sanitizer_mz_destroy;
|
||||
sanitizer_zone.batch_malloc = 0;
|
||||
sanitizer_zone.batch_free = 0;
|
||||
sanitizer_zone.free_definite_size = 0;
|
||||
sanitizer_zone.memalign = &__sanitizer_mz_memalign;
|
||||
sanitizer_zone.introspect = &sanitizer_zone_introspection;
|
||||
|
||||
// Register the zone.
|
||||
malloc_zone_register(&sanitizer_zone);
|
||||
}
|
||||
|
||||
} // namespace COMMON_MALLOC_NAMESPACE
|
@ -95,7 +95,7 @@
|
||||
// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
|
||||
// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
|
||||
#ifndef SANITIZER_CAN_USE_ALLOCATOR64
|
||||
# if defined(__mips64) || (defined(__aarch64__) && SANITIZER_AARCH64_VMA == 39)
|
||||
# if defined(__mips64) || defined(__aarch64__)
|
||||
# define SANITIZER_CAN_USE_ALLOCATOR64 0
|
||||
# else
|
||||
# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
|
||||
@ -103,16 +103,9 @@
|
||||
#endif
|
||||
|
||||
// The range of addresses which can be returned my mmap.
|
||||
// FIXME: this value should be different on different platforms,
|
||||
// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work
|
||||
// but will consume more memory for TwoLevelByteMap.
|
||||
#if defined(__aarch64__)
|
||||
# if SANITIZER_AARCH64_VMA == 39
|
||||
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
|
||||
# elif SANITIZER_AARCH64_VMA == 42
|
||||
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 42)
|
||||
# endif
|
||||
#elif defined(__mips__)
|
||||
// FIXME: this value should be different on different platforms. Larger values
|
||||
// will still work but will consume more memory for TwoLevelByteMap.
|
||||
#if defined(__mips__)
|
||||
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
|
||||
#else
|
||||
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
|
||||
|
@ -131,7 +131,7 @@
|
||||
#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
|
||||
#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
|
||||
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
||||
defined(__powerpc64__) || defined(__aarch64__))
|
||||
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
|
||||
#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
|
||||
#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
|
||||
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
|
||||
@ -218,7 +218,7 @@
|
||||
// FIXME: getline seems to be available on OSX 10.7
|
||||
#define SANITIZER_INTERCEPT_GETLINE SI_FREEBSD || SI_LINUX_NOT_ANDROID
|
||||
|
||||
#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
|
||||
#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_MAC
|
||||
|
||||
#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
|
||||
#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
|
||||
@ -257,6 +257,7 @@
|
||||
#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD
|
||||
#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS
|
||||
#define SANITIZER_INTERCEPT_MINCORE SI_LINUX
|
||||
#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX
|
||||
|
||||
#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX
|
||||
|
||||
|
@ -117,8 +117,11 @@
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
# include <utime.h>
|
||||
# include <sys/ptrace.h>
|
||||
# if defined(__mips64) || defined(__aarch64__)
|
||||
# if defined(__mips64) || defined(__aarch64__) || defined(__arm__)
|
||||
# include <asm/ptrace.h>
|
||||
# ifdef __arm__
|
||||
typedef struct user_fpregs elf_fpregset_t;
|
||||
# endif
|
||||
# endif
|
||||
# include <semaphore.h>
|
||||
#endif
|
||||
@ -302,8 +305,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
|
||||
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
||||
defined(__powerpc64__) || defined(__aarch64__))
|
||||
#if defined(__mips64) || defined(__powerpc64__)
|
||||
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
|
||||
#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
|
||||
unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
|
||||
unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
|
||||
#elif defined(__aarch64__)
|
||||
@ -314,36 +317,51 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
||||
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
|
||||
#endif // __mips64 || __powerpc64__ || __aarch64__
|
||||
#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
|
||||
defined(__aarch64__)
|
||||
defined(__aarch64__) || defined(__arm__)
|
||||
unsigned struct_user_fpxregs_struct_sz = 0;
|
||||
#else
|
||||
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
|
||||
#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__
|
||||
#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__
|
||||
#ifdef __arm__
|
||||
unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
|
||||
#else
|
||||
unsigned struct_user_vfpregs_struct_sz = 0;
|
||||
#endif
|
||||
|
||||
int ptrace_peektext = PTRACE_PEEKTEXT;
|
||||
int ptrace_peekdata = PTRACE_PEEKDATA;
|
||||
int ptrace_peekuser = PTRACE_PEEKUSER;
|
||||
#if defined(PT_GETREGS) && defined(PT_SETREGS)
|
||||
#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \
|
||||
(defined(PT_GETREGS) && defined(PT_SETREGS))
|
||||
int ptrace_getregs = PTRACE_GETREGS;
|
||||
int ptrace_setregs = PTRACE_SETREGS;
|
||||
#else
|
||||
int ptrace_getregs = -1;
|
||||
int ptrace_setregs = -1;
|
||||
#endif
|
||||
#if defined(PT_GETFPREGS) && defined(PT_SETFPREGS)
|
||||
#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \
|
||||
(defined(PT_GETFPREGS) && defined(PT_SETFPREGS))
|
||||
int ptrace_getfpregs = PTRACE_GETFPREGS;
|
||||
int ptrace_setfpregs = PTRACE_SETFPREGS;
|
||||
#else
|
||||
int ptrace_getfpregs = -1;
|
||||
int ptrace_setfpregs = -1;
|
||||
#endif
|
||||
#if defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)
|
||||
#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \
|
||||
(defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS))
|
||||
int ptrace_getfpxregs = PTRACE_GETFPXREGS;
|
||||
int ptrace_setfpxregs = PTRACE_SETFPXREGS;
|
||||
#else
|
||||
int ptrace_getfpxregs = -1;
|
||||
int ptrace_setfpxregs = -1;
|
||||
#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS
|
||||
#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS)
|
||||
int ptrace_getvfpregs = PTRACE_GETVFPREGS;
|
||||
int ptrace_setvfpregs = PTRACE_SETVFPREGS;
|
||||
#else
|
||||
int ptrace_getvfpregs = -1;
|
||||
int ptrace_setvfpregs = -1;
|
||||
#endif
|
||||
int ptrace_geteventmsg = PTRACE_GETEVENTMSG;
|
||||
#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \
|
||||
(defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
|
||||
|
@ -779,10 +779,11 @@ namespace __sanitizer {
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
|
||||
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
||||
defined(__powerpc64__) || defined(__aarch64__))
|
||||
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
|
||||
extern unsigned struct_user_regs_struct_sz;
|
||||
extern unsigned struct_user_fpregs_struct_sz;
|
||||
extern unsigned struct_user_fpxregs_struct_sz;
|
||||
extern unsigned struct_user_vfpregs_struct_sz;
|
||||
|
||||
extern int ptrace_peektext;
|
||||
extern int ptrace_peekdata;
|
||||
@ -793,6 +794,8 @@ namespace __sanitizer {
|
||||
extern int ptrace_setfpregs;
|
||||
extern int ptrace_getfpxregs;
|
||||
extern int ptrace_setfpxregs;
|
||||
extern int ptrace_getvfpregs;
|
||||
extern int ptrace_setvfpregs;
|
||||
extern int ptrace_getsiginfo;
|
||||
extern int ptrace_setsiginfo;
|
||||
extern int ptrace_getregset;
|
||||
|
@ -117,7 +117,7 @@ void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(res, &reserrno))
|
||||
ReportMmapFailureAndDie(size, mem_type, reserrno);
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
|
||||
IncreaseTotalMmap(size);
|
||||
return (void *)res;
|
||||
}
|
||||
@ -141,12 +141,8 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno)) {
|
||||
Report("ERROR: %s failed to "
|
||||
"allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
|
||||
SanitizerToolName, size, size, mem_type, reserrno);
|
||||
CHECK("unable to mmap" && 0);
|
||||
}
|
||||
if (internal_iserror(p, &reserrno))
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
|
||||
IncreaseTotalMmap(size);
|
||||
return (void *)p;
|
||||
}
|
||||
@ -160,10 +156,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
-1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno)) {
|
||||
Report("ERROR: %s failed to "
|
||||
"allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
|
||||
SanitizerToolName, size, size, fixed_addr, reserrno);
|
||||
CHECK("unable to mmap" && 0);
|
||||
char mem_type[30];
|
||||
internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
|
||||
fixed_addr);
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
|
||||
}
|
||||
IncreaseTotalMmap(size);
|
||||
return (void *)p;
|
||||
|
@ -72,6 +72,8 @@ int real_pthread_join(void *th, void **ret);
|
||||
} \
|
||||
} // namespace __sanitizer
|
||||
|
||||
int my_pthread_attr_getstack(void *attr, void **addr, uptr *size);
|
||||
|
||||
int internal_sigaction(int signum, const void *act, void *oldact);
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
@ -226,7 +226,7 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
#if SANITIZER_ANDROID || SANITIZER_GO
|
||||
int GetNamedMappingFd(const char *name, uptr size) {
|
||||
return -1;
|
||||
}
|
||||
@ -274,6 +274,49 @@ void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
|
||||
return (void *)internal_mmap((void *)fixed_addr, size, PROT_NONE, flags, fd,
|
||||
0);
|
||||
}
|
||||
|
||||
// This function is defined elsewhere if we intercepted pthread_attr_getstack.
|
||||
extern "C" {
|
||||
SANITIZER_WEAK_ATTRIBUTE int
|
||||
real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
|
||||
} // extern "C"
|
||||
|
||||
int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) {
|
||||
#if !SANITIZER_GO && !SANITIZER_MAC
|
||||
if (&real_pthread_attr_getstack)
|
||||
return real_pthread_attr_getstack((pthread_attr_t *)attr, addr,
|
||||
(size_t *)size);
|
||||
#endif
|
||||
return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size);
|
||||
}
|
||||
|
||||
#if !SANITIZER_GO
|
||||
void AdjustStackSize(void *attr_) {
|
||||
pthread_attr_t *attr = (pthread_attr_t *)attr_;
|
||||
uptr stackaddr = 0;
|
||||
uptr stacksize = 0;
|
||||
my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
|
||||
// GLibC will return (0 - stacksize) as the stack address in the case when
|
||||
// stacksize is set, but stackaddr is not.
|
||||
bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
|
||||
// We place a lot of tool data into TLS, account for that.
|
||||
const uptr minstacksize = GetTlsSize() + 128*1024;
|
||||
if (stacksize < minstacksize) {
|
||||
if (!stack_set) {
|
||||
if (stacksize != 0) {
|
||||
VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
|
||||
minstacksize);
|
||||
pthread_attr_setstacksize(attr, minstacksize);
|
||||
}
|
||||
} else {
|
||||
Printf("Sanitizer: pre-allocated stack size is insufficient: "
|
||||
"%zu < %zu\n", stacksize, minstacksize);
|
||||
Printf("Sanitizer: pthread_create is likely to fail.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !SANITIZER_GO
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_POSIX
|
||||
|
@ -35,8 +35,14 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
|
||||
return false;
|
||||
bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
|
||||
Dl_info info;
|
||||
int result = dladdr((const void *)addr, &info);
|
||||
if (!result) return false;
|
||||
const char *demangled = DemangleCXXABI(info.dli_sname);
|
||||
datainfo->name = internal_strdup(demangled);
|
||||
datainfo->start = (uptr)info.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
|
||||
class AtosSymbolizerProcess : public SymbolizerProcess {
|
||||
@ -88,7 +94,9 @@ static bool IsAtosErrorMessage(const char *str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
|
||||
static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
|
||||
char **out_module, char **out_file, uptr *line,
|
||||
uptr *start_address) {
|
||||
// Trim ending newlines.
|
||||
char *trim;
|
||||
ExtractTokenUpToDelimiter(str, "\n", &trim);
|
||||
@ -96,7 +104,9 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
|
||||
// The line from `atos` is in one of these formats:
|
||||
// myfunction (in library.dylib) (sourcefile.c:17)
|
||||
// myfunction (in library.dylib) + 0x1fe
|
||||
// myfunction (in library.dylib) + 15
|
||||
// 0xdeadbeef (in library.dylib) + 0x1fe
|
||||
// 0xdeadbeef (in library.dylib) + 15
|
||||
// 0xdeadbeef (in library.dylib)
|
||||
// 0xdeadbeef
|
||||
|
||||
@ -107,21 +117,27 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
|
||||
}
|
||||
|
||||
const char *rest = trim;
|
||||
char *function_name;
|
||||
rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name);
|
||||
if (internal_strncmp(function_name, "0x", 2) != 0)
|
||||
res->info.function = function_name;
|
||||
char *symbol_name;
|
||||
rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
|
||||
if (internal_strncmp(symbol_name, "0x", 2) != 0)
|
||||
*out_name = symbol_name;
|
||||
else
|
||||
InternalFree(function_name);
|
||||
rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module);
|
||||
InternalFree(symbol_name);
|
||||
rest = ExtractTokenUpToDelimiter(rest, ") ", out_module);
|
||||
|
||||
if (rest[0] == '(') {
|
||||
rest++;
|
||||
rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file);
|
||||
char *extracted_line_number;
|
||||
rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
|
||||
res->info.line = internal_atoll(extracted_line_number);
|
||||
InternalFree(extracted_line_number);
|
||||
if (out_file) {
|
||||
rest++;
|
||||
rest = ExtractTokenUpToDelimiter(rest, ":", out_file);
|
||||
char *extracted_line_number;
|
||||
rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
|
||||
if (line) *line = (uptr)internal_atoll(extracted_line_number);
|
||||
InternalFree(extracted_line_number);
|
||||
}
|
||||
} else if (rest[0] == '+') {
|
||||
rest += 2;
|
||||
uptr offset = internal_atoll(rest);
|
||||
if (start_address) *start_address = addr - offset;
|
||||
}
|
||||
|
||||
InternalFree(trim);
|
||||
@ -137,15 +153,30 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
|
||||
internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
|
||||
const char *buf = process_->SendCommand(command);
|
||||
if (!buf) return false;
|
||||
if (!ParseCommandOutput(buf, stack)) {
|
||||
uptr line;
|
||||
if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
|
||||
&stack->info.file, &line, nullptr)) {
|
||||
process_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
stack->info.line = (int)line;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
|
||||
if (!process_) return false;
|
||||
char command[32];
|
||||
internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
|
||||
const char *buf = process_->SendCommand(command);
|
||||
if (!buf) return false;
|
||||
if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr,
|
||||
nullptr, &info->start)) {
|
||||
process_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; }
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
|
@ -444,14 +444,16 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
|
||||
|
||||
if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
|
||||
list->push_back(tool);
|
||||
} else {
|
||||
VReport(2, "No internal or external symbolizer found.\n");
|
||||
}
|
||||
|
||||
#if SANITIZER_MAC
|
||||
VReport(2, "Using dladdr symbolizer.\n");
|
||||
list->push_back(new(*allocator) DlAddrSymbolizer());
|
||||
#endif // SANITIZER_MAC
|
||||
|
||||
if (list->size() == 0) {
|
||||
Report("WARNING: no internal or external symbolizer found.\n");
|
||||
}
|
||||
}
|
||||
|
||||
Symbolizer *Symbolizer::PlatformInit() {
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "sanitizer_platform.h"
|
||||
#if SANITIZER_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
@ -76,6 +76,15 @@ void DTLS_Destroy() {
|
||||
DTLS_Deallocate(dtls.dtv, s);
|
||||
}
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
// This is glibc's TLS_DTV_OFFSET:
|
||||
// "Dynamic thread vector pointers point 0x8000 past the start of each
|
||||
// TLS block."
|
||||
static const uptr kDtvOffset = 0x8000;
|
||||
#else
|
||||
static const uptr kDtvOffset = 0;
|
||||
#endif
|
||||
|
||||
DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
|
||||
uptr static_tls_begin, uptr static_tls_end) {
|
||||
if (!common_flags()->intercept_tls_get_addr) return 0;
|
||||
@ -85,7 +94,7 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
|
||||
DTLS_Resize(dso_id + 1);
|
||||
if (dtls.dtv[dso_id].beg) return 0;
|
||||
uptr tls_size = 0;
|
||||
uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
|
||||
uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
|
||||
VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
|
||||
"num_live_dtls %zd\n",
|
||||
arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
|
||||
|
@ -84,7 +84,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (rv == 0)
|
||||
ReportMmapFailureAndDie(size, mem_type, GetLastError());
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -218,12 +218,14 @@ struct ModuleInfo {
|
||||
uptr end_address;
|
||||
};
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
int CompareModulesBase(const void *pl, const void *pr) {
|
||||
const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
|
||||
if (l->base_address < r->base_address)
|
||||
return -1;
|
||||
return l->base_address > r->base_address;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
@ -364,6 +366,7 @@ static uptr GetPreferredBase(const char *modname) {
|
||||
return (uptr)pe_header->ImageBase;
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
|
||||
string_predicate_t filter) {
|
||||
HANDLE cur_process = GetCurrentProcess();
|
||||
@ -432,7 +435,6 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
|
||||
return count;
|
||||
};
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
// We can't use atexit() directly at __asan_init time as the CRT is not fully
|
||||
// initialized at this point. Place the functions into a vector and use
|
||||
// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
|
||||
|
@ -21,6 +21,8 @@ tsan_files = \
|
||||
tsan_interface_atomic.cc \
|
||||
tsan_interface.cc \
|
||||
tsan_interface_java.cc \
|
||||
tsan_libdispatch_mac.cc \
|
||||
tsan_malloc_mac.cc \
|
||||
tsan_md5.cc \
|
||||
tsan_mman.cc \
|
||||
tsan_mutex.cc \
|
||||
@ -28,6 +30,7 @@ tsan_files = \
|
||||
tsan_new_delete.cc \
|
||||
tsan_platform_linux.cc \
|
||||
tsan_platform_mac.cc \
|
||||
tsan_platform_posix.cc \
|
||||
tsan_platform_windows.cc \
|
||||
tsan_report.cc \
|
||||
tsan_rtl.cc \
|
||||
@ -41,7 +44,7 @@ tsan_files = \
|
||||
tsan_sync.cc
|
||||
|
||||
libtsan_la_SOURCES = $(tsan_files)
|
||||
EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S
|
||||
EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S
|
||||
libtsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
|
||||
libtsan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
|
||||
if LIBBACKTRACE_SUPPORTED
|
||||
|
@ -107,12 +107,14 @@ am__DEPENDENCIES_1 =
|
||||
am__objects_1 = tsan_clock.lo tsan_fd.lo tsan_flags.lo \
|
||||
tsan_ignoreset.lo tsan_interceptors.lo tsan_interface_ann.lo \
|
||||
tsan_interface_atomic.lo tsan_interface.lo \
|
||||
tsan_interface_java.lo tsan_md5.lo tsan_mman.lo tsan_mutex.lo \
|
||||
tsan_interface_java.lo tsan_libdispatch_mac.lo \
|
||||
tsan_malloc_mac.lo tsan_md5.lo tsan_mman.lo tsan_mutex.lo \
|
||||
tsan_mutexset.lo tsan_new_delete.lo tsan_platform_linux.lo \
|
||||
tsan_platform_mac.lo tsan_platform_windows.lo tsan_report.lo \
|
||||
tsan_rtl.lo tsan_rtl_mutex.lo tsan_rtl_report.lo \
|
||||
tsan_rtl_thread.lo tsan_stack_trace.lo tsan_stat.lo \
|
||||
tsan_suppressions.lo tsan_symbolize.lo tsan_sync.lo
|
||||
tsan_platform_mac.lo tsan_platform_posix.lo \
|
||||
tsan_platform_windows.lo tsan_report.lo tsan_rtl.lo \
|
||||
tsan_rtl_mutex.lo tsan_rtl_report.lo tsan_rtl_thread.lo \
|
||||
tsan_stack_trace.lo tsan_stat.lo tsan_suppressions.lo \
|
||||
tsan_symbolize.lo tsan_sync.lo
|
||||
am_libtsan_la_OBJECTS = $(am__objects_1)
|
||||
libtsan_la_OBJECTS = $(am_libtsan_la_OBJECTS)
|
||||
libtsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
|
||||
@ -318,6 +320,8 @@ tsan_files = \
|
||||
tsan_interface_atomic.cc \
|
||||
tsan_interface.cc \
|
||||
tsan_interface_java.cc \
|
||||
tsan_libdispatch_mac.cc \
|
||||
tsan_malloc_mac.cc \
|
||||
tsan_md5.cc \
|
||||
tsan_mman.cc \
|
||||
tsan_mutex.cc \
|
||||
@ -325,6 +329,7 @@ tsan_files = \
|
||||
tsan_new_delete.cc \
|
||||
tsan_platform_linux.cc \
|
||||
tsan_platform_mac.cc \
|
||||
tsan_platform_posix.cc \
|
||||
tsan_platform_windows.cc \
|
||||
tsan_report.cc \
|
||||
tsan_rtl.cc \
|
||||
@ -338,7 +343,7 @@ tsan_files = \
|
||||
tsan_sync.cc
|
||||
|
||||
libtsan_la_SOURCES = $(tsan_files)
|
||||
EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S
|
||||
EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S
|
||||
libtsan_la_LIBADD = \
|
||||
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
|
||||
$(top_builddir)/interception/libinterception.la \
|
||||
@ -473,6 +478,8 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_ann.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_atomic.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_java.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_libdispatch_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_malloc_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_md5.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_mman.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_mutex.Plo@am__quote@
|
||||
@ -480,9 +487,11 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_new_delete.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_posix.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_windows.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_report.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_aarch64.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_amd64.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_mutex.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_report.Plo@am__quote@
|
||||
|
@ -88,8 +88,6 @@
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
const unsigned kInvalidTid = (unsigned)-1;
|
||||
|
||||
ThreadClock::ThreadClock(unsigned tid, unsigned reused)
|
||||
: tid_(tid)
|
||||
, reused_(reused + 1) { // 0 has special meaning
|
||||
|
@ -81,6 +81,8 @@ const bool kCollectHistory = false;
|
||||
const bool kCollectHistory = true;
|
||||
#endif
|
||||
|
||||
const unsigned kInvalidTid = (unsigned)-1;
|
||||
|
||||
// The following "build consistency" machinery ensures that all source files
|
||||
// are built in the same configuration. Inconsistent builds lead to
|
||||
// hard to debug crashes.
|
||||
|
@ -59,9 +59,13 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||
CommonFlags cf;
|
||||
cf.CopyFrom(*common_flags());
|
||||
cf.allow_addr2line = true;
|
||||
#ifndef SANITIZER_GO
|
||||
cf.detect_deadlocks = true;
|
||||
#endif
|
||||
if (kGoMode) {
|
||||
// Does not work as expected for Go: runtime handles SIGABRT and crashes.
|
||||
cf.abort_on_error = false;
|
||||
// Go does not have mutexes.
|
||||
} else {
|
||||
cf.detect_deadlocks = true;
|
||||
}
|
||||
cf.print_suppressions = false;
|
||||
cf.stack_trace_format = " #%n %f %S %M";
|
||||
cf.exitcode = 66;
|
||||
|
@ -26,16 +26,28 @@
|
||||
#include "tsan_mman.h"
|
||||
#include "tsan_fd.h"
|
||||
|
||||
#if SANITIZER_POSIX
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
#endif
|
||||
|
||||
using namespace __tsan; // NOLINT
|
||||
|
||||
#if SANITIZER_FREEBSD
|
||||
#if SANITIZER_FREEBSD || SANITIZER_MAC
|
||||
#define __errno_location __error
|
||||
#define __libc_realloc __realloc
|
||||
#define __libc_calloc __calloc
|
||||
#define stdout __stdoutp
|
||||
#define stderr __stderrp
|
||||
#endif
|
||||
|
||||
#if SANITIZER_FREEBSD
|
||||
#define __libc_realloc __realloc
|
||||
#define __libc_calloc __calloc
|
||||
#elif SANITIZER_MAC
|
||||
#define __libc_malloc REAL(malloc)
|
||||
#define __libc_realloc REAL(realloc)
|
||||
#define __libc_calloc REAL(calloc)
|
||||
#define __libc_free REAL(free)
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
#define PTHREAD_CREATE_DETACHED 1
|
||||
#elif SANITIZER_MAC
|
||||
@ -78,12 +90,13 @@ extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
|
||||
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
|
||||
extern "C" int pthread_setspecific(unsigned key, const void *v);
|
||||
DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
|
||||
extern "C" int pthread_yield();
|
||||
extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set,
|
||||
__sanitizer_sigset_t *oldset);
|
||||
// REAL(sigfillset) defined in common interceptors.
|
||||
DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set)
|
||||
DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
|
||||
extern "C" void *pthread_self();
|
||||
extern "C" void _exit(int status);
|
||||
extern "C" int *__errno_location();
|
||||
@ -100,7 +113,9 @@ const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
|
||||
const int EINVAL = 22;
|
||||
const int EBUSY = 16;
|
||||
const int EOWNERDEAD = 130;
|
||||
#if !SANITIZER_MAC
|
||||
const int EPOLL_CTL_ADD = 1;
|
||||
#endif
|
||||
const int SIGILL = 4;
|
||||
const int SIGABRT = 6;
|
||||
const int SIGFPE = 8;
|
||||
@ -115,7 +130,9 @@ const int SIGBUS = 7;
|
||||
const int SIGSYS = 31;
|
||||
#endif
|
||||
void *const MAP_FAILED = (void*)-1;
|
||||
#if !SANITIZER_MAC
|
||||
const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
|
||||
#endif
|
||||
const int MAP_FIXED = 0x10;
|
||||
typedef long long_t; // NOLINT
|
||||
|
||||
@ -245,17 +262,6 @@ ScopedInterceptor::~ScopedInterceptor() {
|
||||
}
|
||||
}
|
||||
|
||||
#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
|
||||
SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
|
||||
if (REAL(func) == 0) { \
|
||||
Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
|
||||
Die(); \
|
||||
} \
|
||||
if (thr->ignore_interceptors || thr->in_ignored_lib) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
|
||||
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
|
||||
#if SANITIZER_FREEBSD
|
||||
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
|
||||
@ -370,6 +376,7 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
static void on_exit_wrapper(int status, void *arg) {
|
||||
ThreadState *thr = cur_thread();
|
||||
uptr pc = 0;
|
||||
@ -394,6 +401,7 @@ TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
|
||||
ThreadIgnoreEnd(thr, pc);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Cleanup old bufs.
|
||||
static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
|
||||
@ -430,8 +438,12 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
|
||||
static void LongJmp(ThreadState *thr, uptr *env) {
|
||||
#if SANITIZER_FREEBSD
|
||||
uptr mangled_sp = env[2];
|
||||
#else
|
||||
#elif defined(SANITIZER_LINUX)
|
||||
# ifdef __aarch64__
|
||||
uptr mangled_sp = env[13];
|
||||
# else
|
||||
uptr mangled_sp = env[6];
|
||||
# endif
|
||||
#endif // SANITIZER_FREEBSD
|
||||
// Find the saved buf by mangled_sp.
|
||||
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
|
||||
@ -517,6 +529,7 @@ TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
|
||||
REAL(siglongjmp)(env, val);
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
|
||||
if (cur_thread()->in_symbolizer)
|
||||
return __libc_malloc(size);
|
||||
@ -583,6 +596,7 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
|
||||
SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
|
||||
return user_alloc_usable_size(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(uptr, strlen, const char *s) {
|
||||
SCOPED_TSAN_INTERCEPTOR(strlen, s);
|
||||
@ -607,13 +621,18 @@ TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
|
||||
MemoryAccessRange(thr, pc, (uptr)dst, size, true);
|
||||
MemoryAccessRange(thr, pc, (uptr)src, size, false);
|
||||
}
|
||||
return internal_memcpy(dst, src, size);
|
||||
// On OS X, calling internal_memcpy here will cause memory corruptions,
|
||||
// because memcpy and memmove are actually aliases of the same implementation.
|
||||
// We need to use internal_memmove here.
|
||||
return internal_memmove(dst, src, size);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) {
|
||||
SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
|
||||
MemoryAccessRange(thr, pc, (uptr)dst, n, true);
|
||||
MemoryAccessRange(thr, pc, (uptr)src, n, false);
|
||||
if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
|
||||
SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
|
||||
MemoryAccessRange(thr, pc, (uptr)dst, n, true);
|
||||
MemoryAccessRange(thr, pc, (uptr)src, n, false);
|
||||
}
|
||||
return REAL(memmove)(dst, src, n);
|
||||
}
|
||||
|
||||
@ -626,6 +645,7 @@ TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
|
||||
SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
|
||||
char *res = REAL(strchrnul)(s, c);
|
||||
@ -633,6 +653,7 @@ TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
|
||||
READ_STRING(thr, pc, s, len);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(char*, strrchr, char *s, int c) {
|
||||
SCOPED_TSAN_INTERCEPTOR(strrchr, s, c);
|
||||
@ -676,8 +697,8 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
|
||||
int flags, int fd, unsigned off) {
|
||||
TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags,
|
||||
int fd, OFF_T off) {
|
||||
SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off);
|
||||
if (!fix_mmap_addr(&addr, sz, flags))
|
||||
return MAP_FAILED;
|
||||
@ -690,9 +711,9 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
|
||||
int flags, int fd, u64 off) {
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags,
|
||||
int fd, OFF64_T off) {
|
||||
SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
|
||||
if (!fix_mmap_addr(&addr, sz, flags))
|
||||
return MAP_FAILED;
|
||||
@ -720,7 +741,7 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
|
||||
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
|
||||
return user_alloc(thr, pc, sz, align);
|
||||
@ -730,6 +751,7 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
|
||||
#define TSAN_MAYBE_INTERCEPT_MEMALIGN
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
|
||||
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
|
||||
return user_alloc(thr, pc, sz, align);
|
||||
@ -739,8 +761,9 @@ TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
|
||||
SCOPED_INTERCEPTOR_RAW(valloc, sz);
|
||||
return user_alloc(thr, pc, sz, GetPageSizeCached());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
|
||||
SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
|
||||
sz = RoundUp(sz, GetPageSizeCached());
|
||||
@ -751,11 +774,13 @@ TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
|
||||
#define TSAN_MAYBE_INTERCEPT_PVALLOC
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
|
||||
SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
|
||||
*memptr = user_alloc(thr, pc, sz, align);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Used in thread-safe function static initialization.
|
||||
extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
|
||||
@ -785,6 +810,19 @@ extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) {
|
||||
atomic_store(g, 0, memory_order_relaxed);
|
||||
}
|
||||
|
||||
namespace __tsan {
|
||||
void DestroyThreadState() {
|
||||
ThreadState *thr = cur_thread();
|
||||
ThreadFinish(thr);
|
||||
ThreadSignalContext *sctx = thr->signal_ctx;
|
||||
if (sctx) {
|
||||
thr->signal_ctx = 0;
|
||||
UnmapOrDie(sctx, sizeof(*sctx));
|
||||
}
|
||||
cur_thread_finalize();
|
||||
}
|
||||
} // namespace __tsan
|
||||
|
||||
static void thread_finalize(void *v) {
|
||||
uptr iter = (uptr)v;
|
||||
if (iter > 1) {
|
||||
@ -794,15 +832,7 @@ static void thread_finalize(void *v) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
{
|
||||
ThreadState *thr = cur_thread();
|
||||
ThreadFinish(thr);
|
||||
ThreadSignalContext *sctx = thr->signal_ctx;
|
||||
if (sctx) {
|
||||
thr->signal_ctx = 0;
|
||||
UnmapOrDie(sctx, sizeof(*sctx));
|
||||
}
|
||||
}
|
||||
DestroyThreadState();
|
||||
}
|
||||
|
||||
|
||||
@ -829,7 +859,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
|
||||
}
|
||||
ThreadIgnoreEnd(thr, 0);
|
||||
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
|
||||
pthread_yield();
|
||||
internal_sched_yield();
|
||||
ThreadStart(thr, tid, GetTid());
|
||||
atomic_store(&p->tid, 0, memory_order_release);
|
||||
}
|
||||
@ -889,7 +919,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
|
||||
// before the new thread got a chance to acquire from it in ThreadStart.
|
||||
atomic_store(&p.tid, tid, memory_order_release);
|
||||
while (atomic_load(&p.tid, memory_order_acquire) != 0)
|
||||
pthread_yield();
|
||||
internal_sched_yield();
|
||||
}
|
||||
if (attr == &myattr)
|
||||
pthread_attr_destroy(&myattr);
|
||||
@ -1092,6 +1122,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
|
||||
int res = REAL(pthread_mutex_timedlock)(m, abstime);
|
||||
@ -1100,7 +1131,9 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
|
||||
int res = REAL(pthread_spin_init)(m, pshared);
|
||||
@ -1143,6 +1176,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) {
|
||||
int res = REAL(pthread_spin_unlock)(m);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a);
|
||||
@ -1180,6 +1214,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
|
||||
int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
|
||||
@ -1188,6 +1223,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
|
||||
@ -1207,6 +1243,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
|
||||
int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
|
||||
@ -1215,6 +1252,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m);
|
||||
@ -1223,6 +1261,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
|
||||
MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
|
||||
@ -1248,12 +1287,17 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
|
||||
SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
|
||||
if (o == 0 || f == 0)
|
||||
return EINVAL;
|
||||
atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
|
||||
atomic_uint32_t *a;
|
||||
if (!SANITIZER_MAC)
|
||||
a = static_cast<atomic_uint32_t*>(o);
|
||||
else // On OS X, pthread_once_t has a header with a long-sized signature.
|
||||
a = static_cast<atomic_uint32_t*>((void *)((char *)o + sizeof(long_t)));
|
||||
u32 v = atomic_load(a, memory_order_acquire);
|
||||
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
|
||||
memory_order_relaxed)) {
|
||||
@ -1263,7 +1307,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
|
||||
atomic_store(a, 2, memory_order_release);
|
||||
} else {
|
||||
while (v != 2) {
|
||||
pthread_yield();
|
||||
internal_sched_yield();
|
||||
v = atomic_load(a, memory_order_acquire);
|
||||
}
|
||||
if (!thr->in_ignored_lib)
|
||||
@ -1272,7 +1316,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1284,7 +1328,7 @@ TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
|
||||
#if SANITIZER_FREEBSD
|
||||
#if SANITIZER_FREEBSD || SANITIZER_MAC
|
||||
SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
return REAL(stat)(path, buf);
|
||||
@ -1295,7 +1339,7 @@ TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1306,7 +1350,7 @@ TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
|
||||
#define TSAN_MAYBE_INTERCEPT___XSTAT64
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1317,7 +1361,7 @@ TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
|
||||
#define TSAN_MAYBE_INTERCEPT_STAT64
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1329,7 +1373,7 @@ TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
|
||||
#if SANITIZER_FREEBSD
|
||||
#if SANITIZER_FREEBSD || SANITIZER_MAC
|
||||
SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
return REAL(lstat)(path, buf);
|
||||
@ -1340,7 +1384,7 @@ TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1351,7 +1395,7 @@ TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
|
||||
#define TSAN_MAYBE_INTERCEPT___LXSTAT64
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
|
||||
READ_STRING(thr, pc, path, 0);
|
||||
@ -1362,7 +1406,7 @@ TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
|
||||
#define TSAN_MAYBE_INTERCEPT_LSTAT64
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
|
||||
if (fd > 0)
|
||||
@ -1375,7 +1419,7 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
|
||||
#if SANITIZER_FREEBSD
|
||||
#if SANITIZER_FREEBSD || SANITIZER_MAC
|
||||
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
|
||||
if (fd > 0)
|
||||
FdAccess(thr, pc, fd);
|
||||
@ -1388,7 +1432,7 @@ TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
|
||||
if (fd > 0)
|
||||
@ -1400,7 +1444,7 @@ TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
|
||||
#define TSAN_MAYBE_INTERCEPT___FXSTAT64
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
|
||||
if (fd > 0)
|
||||
@ -1421,7 +1465,7 @@ TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
|
||||
SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
|
||||
READ_STRING(thr, pc, name, 0);
|
||||
@ -1444,7 +1488,7 @@ TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
|
||||
SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
|
||||
READ_STRING(thr, pc, name, 0);
|
||||
@ -1474,6 +1518,7 @@ TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) {
|
||||
return newfd2;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags);
|
||||
int newfd2 = REAL(dup3)(oldfd, newfd, flags);
|
||||
@ -1481,8 +1526,9 @@ TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
|
||||
FdDup(thr, pc, oldfd, newfd2, false);
|
||||
return newfd2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
|
||||
int fd = REAL(eventfd)(initval, flags);
|
||||
@ -1495,7 +1541,7 @@ TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
|
||||
#define TSAN_MAYBE_INTERCEPT_EVENTFD
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
|
||||
if (fd >= 0)
|
||||
@ -1510,7 +1556,7 @@ TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
|
||||
#define TSAN_MAYBE_INTERCEPT_SIGNALFD
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, inotify_init, int fake) {
|
||||
SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
|
||||
int fd = REAL(inotify_init)(fake);
|
||||
@ -1523,7 +1569,7 @@ TSAN_INTERCEPTOR(int, inotify_init, int fake) {
|
||||
#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
|
||||
int fd = REAL(inotify_init1)(flags);
|
||||
@ -1577,7 +1623,7 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, epoll_create, int size) {
|
||||
SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
|
||||
int fd = REAL(epoll_create)(size);
|
||||
@ -1590,7 +1636,7 @@ TSAN_INTERCEPTOR(int, epoll_create, int size) {
|
||||
#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
|
||||
int fd = REAL(epoll_create1)(flags);
|
||||
@ -1610,7 +1656,7 @@ TSAN_INTERCEPTOR(int, close, int fd) {
|
||||
return REAL(close)(fd);
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, __close, int fd) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__close, fd);
|
||||
if (fd >= 0)
|
||||
@ -1623,7 +1669,7 @@ TSAN_INTERCEPTOR(int, __close, int fd) {
|
||||
#endif
|
||||
|
||||
// glibc guts
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
|
||||
SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
|
||||
int fds[64];
|
||||
@ -1647,6 +1693,7 @@ TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags);
|
||||
int res = REAL(pipe2)(pipefd, flags);
|
||||
@ -1654,6 +1701,7 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
|
||||
FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
|
||||
SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
|
||||
@ -1704,7 +1752,7 @@ TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
|
||||
SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
|
||||
void *res = REAL(tmpfile64)(fake);
|
||||
@ -1771,7 +1819,7 @@ TSAN_INTERCEPTOR(int, closedir, void *dirp) {
|
||||
return REAL(closedir)(dirp);
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
|
||||
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
|
||||
if (epfd >= 0)
|
||||
@ -1788,7 +1836,7 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
|
||||
#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
|
||||
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
|
||||
if (epfd >= 0)
|
||||
@ -2087,6 +2135,7 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
|
||||
return WRAP(fork)(fake);
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
|
||||
void *data);
|
||||
struct dl_iterate_phdr_data {
|
||||
@ -2130,6 +2179,7 @@ TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) {
|
||||
int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int OnExit(ThreadState *thr) {
|
||||
int status = Finalize(thr);
|
||||
@ -2143,6 +2193,7 @@ struct TsanInterceptorContext {
|
||||
const uptr pc;
|
||||
};
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
static void HandleRecvmsg(ThreadState *thr, uptr pc,
|
||||
__sanitizer_msghdr *msg) {
|
||||
int fds[64];
|
||||
@ -2150,6 +2201,7 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
|
||||
for (int i = 0; i < cnt; i++)
|
||||
FdEventCreate(thr, pc, fds[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
// Causes interceptor recursion (getaddrinfo() and fopen())
|
||||
@ -2264,9 +2316,11 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
|
||||
MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
|
||||
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
|
||||
HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
|
||||
((TsanInterceptorContext *)ctx)->pc, msg)
|
||||
#endif
|
||||
|
||||
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
|
||||
if (TsanThread *t = GetCurrentThread()) { \
|
||||
@ -2298,6 +2352,7 @@ struct ScopedSyscall {
|
||||
}
|
||||
};
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
|
||||
TSAN_SYSCALL();
|
||||
MemoryAccessRange(thr, pc, p, s, write);
|
||||
@ -2351,6 +2406,7 @@ static void syscall_post_fork(uptr pc, int pid) {
|
||||
ForkParentAfter(thr, pc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
|
||||
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
|
||||
@ -2401,24 +2457,29 @@ static void finalize(void *arg) {
|
||||
Die();
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
static void unreachable() {
|
||||
Report("FATAL: ThreadSanitizer: unreachable called\n");
|
||||
Die();
|
||||
}
|
||||
#endif
|
||||
|
||||
void InitializeInterceptors() {
|
||||
#if !SANITIZER_MAC
|
||||
// We need to setup it early, because functions like dlsym() can call it.
|
||||
REAL(memset) = internal_memset;
|
||||
REAL(memcpy) = internal_memcpy;
|
||||
#endif
|
||||
|
||||
// Instruct libc malloc to consume less memory.
|
||||
#if !SANITIZER_FREEBSD
|
||||
#if SANITIZER_LINUX
|
||||
mallopt(1, 0); // M_MXFAST
|
||||
mallopt(-3, 32*1024); // M_MMAP_THRESHOLD
|
||||
#endif
|
||||
|
||||
InitializeCommonInterceptors();
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
// We can not use TSAN_INTERCEPT to get setjmp addr,
|
||||
// because it does &setjmp and setjmp is not present in some versions of libc.
|
||||
using __interception::GetRealFunctionAddress;
|
||||
@ -2426,6 +2487,7 @@ void InitializeInterceptors() {
|
||||
GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
|
||||
GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0);
|
||||
GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
|
||||
#endif
|
||||
|
||||
TSAN_INTERCEPT(longjmp);
|
||||
TSAN_INTERCEPT(siglongjmp);
|
||||
@ -2565,9 +2627,12 @@ void InitializeInterceptors() {
|
||||
TSAN_INTERCEPT(__cxa_atexit);
|
||||
TSAN_INTERCEPT(_exit);
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
// Need to setup it, because interceptors check that the function is resolved.
|
||||
// But atexit is emitted directly into the module, so can't be resolved.
|
||||
REAL(atexit) = (int(*)(void(*)()))unreachable;
|
||||
#endif
|
||||
|
||||
if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
|
||||
Printf("ThreadSanitizer: failed to setup atexit callback\n");
|
||||
Die();
|
||||
|
@ -24,6 +24,18 @@ class ScopedInterceptor {
|
||||
(void)pc; \
|
||||
/**/
|
||||
|
||||
#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
|
||||
SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
|
||||
if (REAL(func) == 0) { \
|
||||
Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
|
||||
Die(); \
|
||||
} \
|
||||
if (thr->ignore_interceptors || thr->in_ignored_lib) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
|
||||
|
||||
#if SANITIZER_FREEBSD
|
||||
#define __libc_free __free
|
||||
#define __libc_malloc __malloc
|
||||
|
70
libsanitizer/tsan/tsan_libdispatch_mac.cc
Normal file
70
libsanitizer/tsan/tsan_libdispatch_mac.cc
Normal file
@ -0,0 +1,70 @@
|
||||
//===-- tsan_libdispatch_mac.cc -------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Mac-specific libdispatch (GCD) support.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_MAC
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "interception/interception.h"
|
||||
#include "tsan_interceptors.h"
|
||||
#include "tsan_platform.h"
|
||||
#include "tsan_rtl.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
// GCD's dispatch_once implementation has a fast path that contains a racy read
|
||||
// and it's inlined into user's code. Furthermore, this fast path doesn't
|
||||
// establish a proper happens-before relations between the initialization and
|
||||
// code following the call to dispatch_once. We could deal with this in
|
||||
// instrumented code, but there's not much we can do about it in system
|
||||
// libraries. Let's disable the fast path (by never storing the value ~0 to
|
||||
// predicate), so the interceptor is always called, and let's add proper release
|
||||
// and acquire semantics. Since TSan does not see its own atomic stores, the
|
||||
// race on predicate won't be reported - the only accesses to it that TSan sees
|
||||
// are the loads on the fast path. Loads don't race. Secondly, dispatch_once is
|
||||
// both a macro and a real function, we want to intercept the function, so we
|
||||
// need to undefine the macro.
|
||||
#undef dispatch_once
|
||||
TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
|
||||
dispatch_block_t block) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_once, predicate, block);
|
||||
atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
|
||||
u32 v = atomic_load(a, memory_order_acquire);
|
||||
if (v == 0 &&
|
||||
atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) {
|
||||
block();
|
||||
Release(thr, pc, (uptr)a);
|
||||
atomic_store(a, 2, memory_order_release);
|
||||
} else {
|
||||
while (v != 2) {
|
||||
internal_sched_yield();
|
||||
v = atomic_load(a, memory_order_acquire);
|
||||
}
|
||||
Acquire(thr, pc, (uptr)a);
|
||||
}
|
||||
}
|
||||
|
||||
#undef dispatch_once_f
|
||||
TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate,
|
||||
void *context, dispatch_function_t function) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_once_f, predicate, context, function);
|
||||
WRAP(dispatch_once)(predicate, ^(void) {
|
||||
function(context);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_MAC
|
67
libsanitizer/tsan/tsan_malloc_mac.cc
Normal file
67
libsanitizer/tsan/tsan_malloc_mac.cc
Normal file
@ -0,0 +1,67 @@
|
||||
//===-- tsan_malloc_mac.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Mac-specific malloc interception.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_MAC
|
||||
|
||||
#include "tsan_interceptors.h"
|
||||
#include "tsan_stack_trace.h"
|
||||
|
||||
using namespace __tsan;
|
||||
#define COMMON_MALLOC_ZONE_NAME "tsan"
|
||||
#define COMMON_MALLOC_ENTER()
|
||||
#define COMMON_MALLOC_SANITIZER_INITIALIZED (cur_thread()->is_inited)
|
||||
#define COMMON_MALLOC_FORCE_LOCK()
|
||||
#define COMMON_MALLOC_FORCE_UNLOCK()
|
||||
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
|
||||
void *p = \
|
||||
user_alloc(cur_thread(), StackTrace::GetCurrentPc(), size, alignment)
|
||||
#define COMMON_MALLOC_MALLOC(size) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return REAL(malloc)(size); \
|
||||
SCOPED_INTERCEPTOR_RAW(malloc, size); \
|
||||
void *p = user_alloc(thr, pc, size)
|
||||
#define COMMON_MALLOC_REALLOC(ptr, size) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return REAL(realloc)(ptr, size); \
|
||||
SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \
|
||||
void *p = user_realloc(thr, pc, ptr, size)
|
||||
#define COMMON_MALLOC_CALLOC(count, size) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return REAL(calloc)(count, size); \
|
||||
SCOPED_INTERCEPTOR_RAW(calloc, size, count); \
|
||||
void *p = user_calloc(thr, pc, size, count)
|
||||
#define COMMON_MALLOC_VALLOC(size) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return REAL(valloc)(size); \
|
||||
SCOPED_INTERCEPTOR_RAW(valloc, size); \
|
||||
void *p = user_alloc(thr, pc, size, GetPageSizeCached())
|
||||
#define COMMON_MALLOC_FREE(ptr) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return REAL(free)(ptr); \
|
||||
SCOPED_INTERCEPTOR_RAW(free, ptr); \
|
||||
user_free(thr, pc, ptr)
|
||||
#define COMMON_MALLOC_SIZE(ptr) \
|
||||
uptr size = user_alloc_usable_size(ptr);
|
||||
#define COMMON_MALLOC_FILL_STATS(zone, stats)
|
||||
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
|
||||
(void)zone_name; \
|
||||
Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
|
||||
#define COMMON_MALLOC_IGNORE_INVALID_FREE false
|
||||
#define COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name) \
|
||||
(void)zone_name; \
|
||||
Report("free_common(%p) -- attempting to free unallocated memory.\n", ptr);
|
||||
#define COMMON_MALLOC_NAMESPACE __tsan
|
||||
|
||||
#include "sanitizer_common/sanitizer_malloc_mac.inc"
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@ namespace __tsan {
|
||||
const uptr kDefaultAlignment = 16;
|
||||
|
||||
void InitializeAllocator();
|
||||
void ReplaceSystemMalloc();
|
||||
void AllocatorThreadStart(ThreadState *thr);
|
||||
void AllocatorThreadFinish(ThreadState *thr);
|
||||
void AllocatorPrintStats();
|
||||
|
@ -9,6 +9,7 @@
|
||||
//
|
||||
// Interceptors for operators new and delete.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "tsan_interceptors.h"
|
||||
|
||||
@ -18,6 +19,13 @@ namespace std {
|
||||
struct nothrow_t {};
|
||||
} // namespace std
|
||||
|
||||
DECLARE_REAL(void *, malloc, uptr size)
|
||||
DECLARE_REAL(void, free, void *ptr)
|
||||
#if SANITIZER_MAC
|
||||
#define __libc_malloc REAL(malloc)
|
||||
#define __libc_free REAL(free)
|
||||
#endif
|
||||
|
||||
#define OPERATOR_NEW_BODY(mangled_name) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return __libc_malloc(size); \
|
||||
|
@ -338,6 +338,8 @@ uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
|
||||
}
|
||||
|
||||
void InitializePlatform();
|
||||
void CheckAndProtect();
|
||||
void InitializeShadowMemoryPlatform();
|
||||
void FlushShadowMemory();
|
||||
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
|
||||
|
||||
@ -351,6 +353,8 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
|
||||
void *abstime), void *c, void *m, void *abstime,
|
||||
void(*cleanup)(void *arg), void *arg);
|
||||
|
||||
void DestroyThreadState();
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // TSAN_PLATFORM_H
|
||||
|
@ -130,17 +130,6 @@ void FlushShadowMemory() {
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
static void ProtectRange(uptr beg, uptr end) {
|
||||
CHECK_LE(beg, end);
|
||||
if (beg == end)
|
||||
return;
|
||||
if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
|
||||
Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
|
||||
Printf("FATAL: Make sure you are not using unlimited stack\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
// Mark shadow for .rodata sections with the special kShadowRodata marker.
|
||||
// Accesses to .rodata can't race, so this saves time, memory and trace space.
|
||||
static void MapRodata() {
|
||||
@ -198,58 +187,7 @@ static void MapRodata() {
|
||||
internal_close(fd);
|
||||
}
|
||||
|
||||
void InitializeShadowMemory() {
|
||||
// Map memory shadow.
|
||||
uptr shadow =
|
||||
(uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg, "shadow");
|
||||
if (shadow != kShadowBeg) {
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie (%p, %p).\n", shadow, kShadowBeg);
|
||||
Die();
|
||||
}
|
||||
// This memory range is used for thread stacks and large user mmaps.
|
||||
// Frequently a thread uses only a small part of stack and similarly
|
||||
// a program uses a small part of large mmap. On some programs
|
||||
// we see 20% memory usage reduction without huge pages for this range.
|
||||
// FIXME: don't use constants here.
|
||||
#if defined(__x86_64__)
|
||||
const uptr kMadviseRangeBeg = 0x7f0000000000ull;
|
||||
const uptr kMadviseRangeSize = 0x010000000000ull;
|
||||
#elif defined(__mips64)
|
||||
const uptr kMadviseRangeBeg = 0xff00000000ull;
|
||||
const uptr kMadviseRangeSize = 0x0100000000ull;
|
||||
#elif defined(__aarch64__)
|
||||
const uptr kMadviseRangeBeg = 0x7e00000000ull;
|
||||
const uptr kMadviseRangeSize = 0x0100000000ull;
|
||||
#endif
|
||||
NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
|
||||
kMadviseRangeSize * kShadowMultiplier);
|
||||
// Meta shadow is compressing and we don't flush it,
|
||||
// so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory.
|
||||
// On one program it reduces memory consumption from 5GB to 2.5GB.
|
||||
NoHugePagesInRegion(kMetaShadowBeg, kMetaShadowEnd - kMetaShadowBeg);
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
|
||||
DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
|
||||
kShadowBeg, kShadowEnd,
|
||||
(kShadowEnd - kShadowBeg) >> 30);
|
||||
|
||||
// Map meta shadow.
|
||||
uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
|
||||
uptr meta =
|
||||
(uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size, "meta shadow");
|
||||
if (meta != kMetaShadowBeg) {
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
|
||||
Die();
|
||||
}
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(meta, meta_size);
|
||||
DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
|
||||
meta, meta + meta_size, meta_size >> 30);
|
||||
|
||||
void InitializeShadowMemoryPlatform() {
|
||||
MapRodata();
|
||||
}
|
||||
|
||||
@ -293,31 +231,6 @@ static void InitDataSeg() {
|
||||
CHECK_LT((uptr)&g_data_start, g_data_end);
|
||||
}
|
||||
|
||||
static void CheckAndProtect() {
|
||||
// Ensure that the binary is indeed compiled with -pie.
|
||||
MemoryMappingLayout proc_maps(true);
|
||||
uptr p, end;
|
||||
while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
|
||||
if (IsAppMem(p))
|
||||
continue;
|
||||
if (p >= kHeapMemEnd &&
|
||||
p < HeapEnd())
|
||||
continue;
|
||||
if (p >= kVdsoBeg) // vdso
|
||||
break;
|
||||
Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
|
||||
Die();
|
||||
}
|
||||
|
||||
ProtectRange(kLoAppMemEnd, kShadowBeg);
|
||||
ProtectRange(kShadowEnd, kMetaShadowBeg);
|
||||
ProtectRange(kMetaShadowEnd, kTraceMemBeg);
|
||||
// Memory for traces is mapped lazily in MapThreadTrace.
|
||||
// Protect the whole range for now, so that user does not map something here.
|
||||
ProtectRange(kTraceMemBeg, kTraceMemEnd);
|
||||
ProtectRange(kTraceMemEnd, kHeapMemBeg);
|
||||
ProtectRange(HeapEnd(), kHiAppMemBeg);
|
||||
}
|
||||
#endif // #ifndef SANITIZER_GO
|
||||
|
||||
void InitializePlatform() {
|
||||
@ -416,6 +329,10 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
void ReplaceSystemMalloc() { }
|
||||
#endif
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
|
@ -13,8 +13,10 @@
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_MAC
|
||||
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "tsan_platform.h"
|
||||
#include "tsan_rtl.h"
|
||||
@ -38,6 +40,62 @@
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
|
||||
atomic_uintptr_t *a = (atomic_uintptr_t *)dst;
|
||||
void *val = (void *)atomic_load_relaxed(a);
|
||||
atomic_signal_fence(memory_order_acquire); // Turns the previous load into
|
||||
// acquire wrt signals.
|
||||
if (UNLIKELY(val == nullptr)) {
|
||||
val = (void *)internal_mmap(nullptr, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
CHECK(val);
|
||||
void *cmp = nullptr;
|
||||
if (!atomic_compare_exchange_strong(a, (uintptr_t *)&cmp, (uintptr_t)val,
|
||||
memory_order_acq_rel)) {
|
||||
internal_munmap(val, size);
|
||||
val = cmp;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
// On OS X, accessing TLVs via __thread or manually by using pthread_key_* is
|
||||
// problematic, because there are several places where interceptors are called
|
||||
// when TLVs are not accessible (early process startup, thread cleanup, ...).
|
||||
// The following provides a "poor man's TLV" implementation, where we use the
|
||||
// shadow memory of the pointer returned by pthread_self() to store a pointer to
|
||||
// the ThreadState object. The main thread's ThreadState pointer is stored
|
||||
// separately in a static variable, because we need to access it even before the
|
||||
// shadow memory is set up.
|
||||
static uptr main_thread_identity = 0;
|
||||
static ThreadState *main_thread_state = nullptr;
|
||||
|
||||
ThreadState *cur_thread() {
|
||||
ThreadState **fake_tls;
|
||||
uptr thread_identity = (uptr)pthread_self();
|
||||
if (thread_identity == main_thread_identity || main_thread_identity == 0) {
|
||||
fake_tls = &main_thread_state;
|
||||
} else {
|
||||
fake_tls = (ThreadState **)MemToShadow(thread_identity);
|
||||
}
|
||||
ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
|
||||
(uptr *)fake_tls, sizeof(ThreadState));
|
||||
return thr;
|
||||
}
|
||||
|
||||
// TODO(kuba.brecka): This is not async-signal-safe. In particular, we call
|
||||
// munmap first and then clear `fake_tls`; if we receive a signal in between,
|
||||
// handler will try to access the unmapped ThreadState.
|
||||
void cur_thread_finalize() {
|
||||
uptr thread_identity = (uptr)pthread_self();
|
||||
CHECK_NE(thread_identity, main_thread_identity);
|
||||
ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
|
||||
internal_munmap(*fake_tls, sizeof(ThreadState));
|
||||
*fake_tls = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
uptr GetShadowMemoryConsumption() {
|
||||
return 0;
|
||||
}
|
||||
@ -49,28 +107,57 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
void InitializeShadowMemory() {
|
||||
uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
|
||||
kShadowEnd - kShadowBeg);
|
||||
if (shadow != kShadowBeg) {
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie.\n");
|
||||
Die();
|
||||
void InitializeShadowMemoryPlatform() { }
|
||||
|
||||
// On OS X, GCD worker threads are created without a call to pthread_create. We
|
||||
// need to properly register these threads with ThreadCreate and ThreadStart.
|
||||
// These threads don't have a parent thread, as they are created "spuriously".
|
||||
// We're using a libpthread API that notifies us about a newly created thread.
|
||||
// The `thread == pthread_self()` check indicates this is actually a worker
|
||||
// thread. If it's just a regular thread, this hook is called on the parent
|
||||
// thread.
|
||||
typedef void (*pthread_introspection_hook_t)(unsigned int event,
|
||||
pthread_t thread, void *addr,
|
||||
size_t size);
|
||||
extern "C" pthread_introspection_hook_t pthread_introspection_hook_install(
|
||||
pthread_introspection_hook_t hook);
|
||||
static const uptr PTHREAD_INTROSPECTION_THREAD_CREATE = 1;
|
||||
static const uptr PTHREAD_INTROSPECTION_THREAD_DESTROY = 4;
|
||||
static pthread_introspection_hook_t prev_pthread_introspection_hook;
|
||||
static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
|
||||
void *addr, size_t size) {
|
||||
if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
|
||||
if (thread == pthread_self()) {
|
||||
// The current thread is a newly created GCD worker thread.
|
||||
ThreadState *parent_thread_state = nullptr; // No parent.
|
||||
int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
|
||||
CHECK_NE(tid, 0);
|
||||
ThreadState *thr = cur_thread();
|
||||
ThreadStart(thr, tid, GetTid());
|
||||
}
|
||||
} else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
|
||||
ThreadState *thr = cur_thread();
|
||||
if (thr->tctx && thr->tctx->parent_tid == kInvalidTid) {
|
||||
DestroyThreadState();
|
||||
}
|
||||
}
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
|
||||
DPrintf("kShadow %zx-%zx (%zuGB)\n",
|
||||
kShadowBeg, kShadowEnd,
|
||||
(kShadowEnd - kShadowBeg) >> 30);
|
||||
DPrintf("kAppMem %zx-%zx (%zuGB)\n",
|
||||
kAppMemBeg, kAppMemEnd,
|
||||
(kAppMemEnd - kAppMemBeg) >> 30);
|
||||
|
||||
if (prev_pthread_introspection_hook != nullptr)
|
||||
prev_pthread_introspection_hook(event, thread, addr, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
void InitializePlatform() {
|
||||
DisableCoreDumperIfNecessary();
|
||||
#ifndef SANITIZER_GO
|
||||
CheckAndProtect();
|
||||
|
||||
CHECK_EQ(main_thread_identity, 0);
|
||||
main_thread_identity = (uptr)pthread_self();
|
||||
|
||||
prev_pthread_introspection_hook =
|
||||
pthread_introspection_hook_install(&my_pthread_introspection_hook);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
@ -89,6 +176,10 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsGlobalVar(uptr addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
|
122
libsanitizer/tsan/tsan_platform_posix.cc
Normal file
122
libsanitizer/tsan/tsan_platform_posix.cc
Normal file
@ -0,0 +1,122 @@
|
||||
//===-- tsan_platform_posix.cc --------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// POSIX-specific code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_POSIX
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "tsan_platform.h"
|
||||
#include "tsan_rtl.h"
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
void InitializeShadowMemory() {
|
||||
// Map memory shadow.
|
||||
uptr shadow =
|
||||
(uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg, "shadow");
|
||||
if (shadow != kShadowBeg) {
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie (%p, %p).\n", shadow, kShadowBeg);
|
||||
Die();
|
||||
}
|
||||
// This memory range is used for thread stacks and large user mmaps.
|
||||
// Frequently a thread uses only a small part of stack and similarly
|
||||
// a program uses a small part of large mmap. On some programs
|
||||
// we see 20% memory usage reduction without huge pages for this range.
|
||||
// FIXME: don't use constants here.
|
||||
#if defined(__x86_64__)
|
||||
const uptr kMadviseRangeBeg = 0x7f0000000000ull;
|
||||
const uptr kMadviseRangeSize = 0x010000000000ull;
|
||||
#elif defined(__mips64)
|
||||
const uptr kMadviseRangeBeg = 0xff00000000ull;
|
||||
const uptr kMadviseRangeSize = 0x0100000000ull;
|
||||
#elif defined(__aarch64__)
|
||||
const uptr kMadviseRangeBeg = 0x7e00000000ull;
|
||||
const uptr kMadviseRangeSize = 0x0100000000ull;
|
||||
#endif
|
||||
NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
|
||||
kMadviseRangeSize * kShadowMultiplier);
|
||||
// Meta shadow is compressing and we don't flush it,
|
||||
// so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory.
|
||||
// On one program it reduces memory consumption from 5GB to 2.5GB.
|
||||
NoHugePagesInRegion(kMetaShadowBeg, kMetaShadowEnd - kMetaShadowBeg);
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
|
||||
DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
|
||||
kShadowBeg, kShadowEnd,
|
||||
(kShadowEnd - kShadowBeg) >> 30);
|
||||
|
||||
// Map meta shadow.
|
||||
uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
|
||||
uptr meta =
|
||||
(uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size, "meta shadow");
|
||||
if (meta != kMetaShadowBeg) {
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
|
||||
Die();
|
||||
}
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(meta, meta_size);
|
||||
DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
|
||||
meta, meta + meta_size, meta_size >> 30);
|
||||
|
||||
InitializeShadowMemoryPlatform();
|
||||
}
|
||||
|
||||
static void ProtectRange(uptr beg, uptr end) {
|
||||
CHECK_LE(beg, end);
|
||||
if (beg == end)
|
||||
return;
|
||||
if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
|
||||
Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
|
||||
Printf("FATAL: Make sure you are not using unlimited stack\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckAndProtect() {
|
||||
// Ensure that the binary is indeed compiled with -pie.
|
||||
MemoryMappingLayout proc_maps(true);
|
||||
uptr p, end, prot;
|
||||
while (proc_maps.Next(&p, &end, 0, 0, 0, &prot)) {
|
||||
if (IsAppMem(p))
|
||||
continue;
|
||||
if (p >= kHeapMemEnd &&
|
||||
p < HeapEnd())
|
||||
continue;
|
||||
if (prot == 0) // Zero page or mprotected.
|
||||
continue;
|
||||
if (p >= kVdsoBeg) // vdso
|
||||
break;
|
||||
Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
|
||||
Die();
|
||||
}
|
||||
|
||||
ProtectRange(kLoAppMemEnd, kShadowBeg);
|
||||
ProtectRange(kShadowEnd, kMetaShadowBeg);
|
||||
ProtectRange(kMetaShadowEnd, kTraceMemBeg);
|
||||
// Memory for traces is mapped lazily in MapThreadTrace.
|
||||
// Protect the whole range for now, so that user does not map something here.
|
||||
ProtectRange(kTraceMemBeg, kTraceMemEnd);
|
||||
ProtectRange(kTraceMemEnd, kHeapMemBeg);
|
||||
ProtectRange(HeapEnd(), kHiAppMemBeg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_POSIX
|
@ -109,6 +109,12 @@ static const char *ReportTypeString(ReportType typ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
#if SANITIZER_MAC
|
||||
static const char *const kInterposedFunctionPrefix = "wrap_";
|
||||
#else
|
||||
static const char *const kInterposedFunctionPrefix = "__interceptor_";
|
||||
#endif
|
||||
|
||||
void PrintStack(const ReportStack *ent) {
|
||||
if (ent == 0 || ent->frames == 0) {
|
||||
Printf(" [failed to restore the stack]\n\n");
|
||||
@ -119,7 +125,7 @@ void PrintStack(const ReportStack *ent) {
|
||||
InternalScopedString res(2 * GetPageSizeCached());
|
||||
RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
|
||||
common_flags()->symbolize_vs_style,
|
||||
common_flags()->strip_path_prefix, "__interceptor_");
|
||||
common_flags()->strip_path_prefix, kInterposedFunctionPrefix);
|
||||
Printf("%s\n", res.data());
|
||||
}
|
||||
Printf("\n");
|
||||
@ -163,9 +169,14 @@ static void PrintLocation(const ReportLocation *loc) {
|
||||
Printf("%s", d.Location());
|
||||
if (loc->type == ReportLocationGlobal) {
|
||||
const DataInfo &global = loc->global;
|
||||
Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
|
||||
global.name, global.size, global.start,
|
||||
StripModuleName(global.module), global.module_offset);
|
||||
if (global.size != 0)
|
||||
Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
|
||||
global.name, global.size, global.start,
|
||||
StripModuleName(global.module), global.module_offset);
|
||||
else
|
||||
Printf(" Location is global '%s' at %p (%s+%p)\n\n", global.name,
|
||||
global.start, StripModuleName(global.module),
|
||||
global.module_offset);
|
||||
} else if (loc->type == ReportLocationHeap) {
|
||||
char thrbuf[kThreadBufSize];
|
||||
Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
|
||||
|
@ -42,7 +42,7 @@ extern "C" void __tsan_resume() {
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
#if !defined(SANITIZER_GO) && !SANITIZER_MAC
|
||||
THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
|
||||
#endif
|
||||
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
|
||||
@ -323,6 +323,7 @@ void Initialize(ThreadState *thr) {
|
||||
CheckVMASize();
|
||||
#ifndef SANITIZER_GO
|
||||
InitializeAllocator();
|
||||
ReplaceSystemMalloc();
|
||||
#endif
|
||||
InitializeInterceptors();
|
||||
CheckShadowMapping();
|
||||
|
@ -408,12 +408,18 @@ struct ThreadState {
|
||||
};
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
#if SANITIZER_MAC
|
||||
ThreadState *cur_thread();
|
||||
void cur_thread_finalize();
|
||||
#else
|
||||
__attribute__((tls_model("initial-exec")))
|
||||
extern THREADLOCAL char cur_thread_placeholder[];
|
||||
INLINE ThreadState *cur_thread() {
|
||||
return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
|
||||
}
|
||||
#endif
|
||||
INLINE void cur_thread_finalize() { }
|
||||
#endif // SANITIZER_MAC
|
||||
#endif // SANITIZER_GO
|
||||
|
||||
class ThreadContext : public ThreadContextBase {
|
||||
public:
|
||||
@ -707,7 +713,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
|
||||
// The trick is that the call preserves all registers and the compiler
|
||||
// does not treat it as a call.
|
||||
// If it does not work for you, use normal call.
|
||||
#if !SANITIZER_DEBUG && defined(__x86_64__)
|
||||
#if !SANITIZER_DEBUG && defined(__x86_64__) && !SANITIZER_MAC
|
||||
// The caller may not create the stack frame for itself at all,
|
||||
// so we create a reserve stack frame for it (1024b must be enough).
|
||||
#define HACKY_CALL(f) \
|
||||
|
204
libsanitizer/tsan/tsan_rtl_aarch64.S
Normal file
204
libsanitizer/tsan/tsan_rtl_aarch64.S
Normal file
@ -0,0 +1,204 @@
|
||||
#include "sanitizer_common/sanitizer_asm.h"
|
||||
.hidden __tsan_setjmp
|
||||
.comm _ZN14__interception11real_setjmpE,8,8
|
||||
.type setjmp, @function
|
||||
setjmp:
|
||||
CFI_STARTPROC
|
||||
|
||||
// save env parameters for function call
|
||||
stp x29, x30, [sp, -32]!
|
||||
CFI_DEF_CFA_OFFSET (32)
|
||||
CFI_OFFSET (29, -32)
|
||||
CFI_OFFSET (30, -24)
|
||||
|
||||
// Adjust the SP for previous frame
|
||||
add x29, sp, 0
|
||||
CFI_DEF_CFA_REGISTER (29)
|
||||
|
||||
// Save jmp_buf
|
||||
str x19, [sp, 16]
|
||||
CFI_OFFSET (19, -16)
|
||||
mov x19, x0
|
||||
|
||||
// SP pointer mangling (see glibc setjmp)
|
||||
adrp x2, :got:__pointer_chk_guard
|
||||
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
|
||||
add x0, x29, 32
|
||||
ldr x2, [x2]
|
||||
eor x1, x2, x0
|
||||
|
||||
// call tsan interceptor
|
||||
bl __tsan_setjmp
|
||||
|
||||
// restore env parameter
|
||||
mov x0, x19
|
||||
ldr x19, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
CFI_RESTORE (30)
|
||||
CFI_RESTORE (19)
|
||||
CFI_DEF_CFA (31, 0)
|
||||
|
||||
// tail jump to libc setjmp
|
||||
adrp x1, :got:_ZN14__interception11real_setjmpE
|
||||
ldr x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE]
|
||||
ldr x1, [x1]
|
||||
br x1
|
||||
|
||||
CFI_ENDPROC
|
||||
.size setjmp, .-setjmp
|
||||
|
||||
.comm _ZN14__interception12real__setjmpE,8,8
|
||||
.globl _setjmp
|
||||
.type _setjmp, @function
|
||||
_setjmp:
|
||||
CFI_STARTPROC
|
||||
|
||||
// save env parameters for function call
|
||||
stp x29, x30, [sp, -32]!
|
||||
CFI_DEF_CFA_OFFSET (32)
|
||||
CFI_OFFSET (29, -32)
|
||||
CFI_OFFSET (30, -24)
|
||||
|
||||
// Adjust the SP for previous frame
|
||||
add x29, sp, 0
|
||||
CFI_DEF_CFA_REGISTER (29)
|
||||
|
||||
// Save jmp_buf
|
||||
str x19, [sp, 16]
|
||||
CFI_OFFSET (19, -16)
|
||||
mov x19, x0
|
||||
|
||||
// SP pointer mangling (see glibc setjmp)
|
||||
adrp x2, :got:__pointer_chk_guard
|
||||
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
|
||||
add x0, x29, 32
|
||||
ldr x2, [x2]
|
||||
eor x1, x2, x0
|
||||
|
||||
// call tsan interceptor
|
||||
bl __tsan_setjmp
|
||||
|
||||
// Restore jmp_buf parameter
|
||||
mov x0, x19
|
||||
ldr x19, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
CFI_RESTORE (30)
|
||||
CFI_RESTORE (19)
|
||||
CFI_DEF_CFA (31, 0)
|
||||
|
||||
// tail jump to libc setjmp
|
||||
adrp x1, :got:_ZN14__interception12real__setjmpE
|
||||
ldr x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE]
|
||||
ldr x1, [x1]
|
||||
br x1
|
||||
|
||||
CFI_ENDPROC
|
||||
.size _setjmp, .-_setjmp
|
||||
|
||||
.comm _ZN14__interception14real_sigsetjmpE,8,8
|
||||
.globl sigsetjmp
|
||||
.type sigsetjmp, @function
|
||||
sigsetjmp:
|
||||
CFI_STARTPROC
|
||||
|
||||
// save env parameters for function call
|
||||
stp x29, x30, [sp, -32]!
|
||||
CFI_DEF_CFA_OFFSET (32)
|
||||
CFI_OFFSET (29, -32)
|
||||
CFI_OFFSET (30, -24)
|
||||
|
||||
// Adjust the SP for previous frame
|
||||
add x29, sp, 0
|
||||
CFI_DEF_CFA_REGISTER (29)
|
||||
|
||||
// Save jmp_buf and savesigs
|
||||
stp x19, x20, [sp, 16]
|
||||
CFI_OFFSET (19, -16)
|
||||
CFI_OFFSET (20, -8)
|
||||
mov w20, w1
|
||||
mov x19, x0
|
||||
|
||||
// SP pointer mangling (see glibc setjmp)
|
||||
adrp x2, :got:__pointer_chk_guard
|
||||
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
|
||||
add x0, x29, 32
|
||||
ldr x2, [x2]
|
||||
eor x1, x2, x0
|
||||
|
||||
// call tsan interceptor
|
||||
bl __tsan_setjmp
|
||||
|
||||
// restore env parameter
|
||||
mov w1, w20
|
||||
mov x0, x19
|
||||
ldp x19, x20, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
CFI_RESTORE (30)
|
||||
CFI_RESTORE (29)
|
||||
CFI_RESTORE (19)
|
||||
CFI_RESTORE (20)
|
||||
CFI_DEF_CFA (31, 0)
|
||||
|
||||
// tail jump to libc sigsetjmp
|
||||
adrp x2, :got:_ZN14__interception14real_sigsetjmpE
|
||||
ldr x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE]
|
||||
ldr x2, [x2]
|
||||
br x2
|
||||
CFI_ENDPROC
|
||||
.size sigsetjmp, .-sigsetjmp
|
||||
|
||||
.comm _ZN14__interception16real___sigsetjmpE,8,8
|
||||
.globl __sigsetjmp
|
||||
.type __sigsetjmp, @function
|
||||
__sigsetjmp:
|
||||
CFI_STARTPROC
|
||||
|
||||
// save env parameters for function call
|
||||
stp x29, x30, [sp, -32]!
|
||||
CFI_DEF_CFA_OFFSET (32)
|
||||
CFI_OFFSET (29, -32)
|
||||
CFI_OFFSET (30, -24)
|
||||
|
||||
// Adjust the SP for previous frame
|
||||
add x29, sp, 0
|
||||
CFI_DEF_CFA_REGISTER (29)
|
||||
|
||||
// Save jmp_buf and savesigs
|
||||
stp x19, x20, [sp, 16]
|
||||
CFI_OFFSET (19, -16)
|
||||
CFI_OFFSET (20, -8)
|
||||
mov w20, w1
|
||||
mov x19, x0
|
||||
|
||||
// SP pointer mangling (see glibc setjmp)
|
||||
adrp x2, :got:__pointer_chk_guard
|
||||
ldr x2, [x2, #:got_lo12:__pointer_chk_guard]
|
||||
add x0, x29, 32
|
||||
ldr x2, [x2]
|
||||
eor x1, x2, x0
|
||||
|
||||
// call tsan interceptor
|
||||
bl __tsan_setjmp
|
||||
|
||||
mov w1, w20
|
||||
mov x0, x19
|
||||
ldp x19, x20, [sp, 16]
|
||||
ldp x29, x30, [sp], 32
|
||||
CFI_RESTORE (30)
|
||||
CFI_RESTORE (29)
|
||||
CFI_RESTORE (19)
|
||||
CFI_RESTORE (20)
|
||||
CFI_DEF_CFA (31, 0)
|
||||
|
||||
// tail jump to libc __sigsetjmp
|
||||
adrp x2, :got:_ZN14__interception16real___sigsetjmpE
|
||||
ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE]
|
||||
ldr x2, [x2]
|
||||
br x2
|
||||
CFI_ENDPROC
|
||||
.size __sigsetjmp, .-__sigsetjmp
|
||||
|
||||
#if defined(__linux__)
|
||||
/* We do not need executable stack. */
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
@ -53,6 +53,8 @@ void ThreadContext::OnCreated(void *arg) {
|
||||
if (tid == 0)
|
||||
return;
|
||||
OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
|
||||
if (!args->thr) // GCD workers don't have a parent thread.
|
||||
return;
|
||||
args->thr->fast_state.IncrementEpoch();
|
||||
// Can't increment epoch w/o writing to the trace as well.
|
||||
TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
|
||||
@ -229,8 +231,10 @@ int ThreadCount(ThreadState *thr) {
|
||||
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
|
||||
StatInc(thr, StatThreadCreate);
|
||||
OnCreatedArgs args = { thr, pc };
|
||||
int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
|
||||
DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
|
||||
u32 parent_tid = thr ? thr->tid : kInvalidTid; // No parent for GCD workers.
|
||||
int tid =
|
||||
ctx->thread_registry->CreateThread(uid, detached, parent_tid, &args);
|
||||
DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid);
|
||||
StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
|
||||
return tid;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user