Commit 866e32ad by Kostya Serebryany Committed by Kostya Serebryany

[libsanitizer merge from upstream r218156]

From-SVN: r215527
parent e8ee4054
2014-09-23 Kostya Serebryany <kcc@google.com>
Update to match the changed asan API.
* asan.c (asan_global_struct): Update the __asan_global definition
to match the new API.
(asan_add_global): Ditto.
* sanitizer.def (BUILT_IN_ASAN_INIT): Rename __asan_init_v3
to __asan_init_v4.
2014-09-23 Michael Meissner <meissner@linux.vnet.ibm.com>
* config/rs6000/rs6000.md (f32_vsx): New mode attributes to
......@@ -230,6 +230,9 @@ along with GCC; see the file COPYING3. If not see
// 1 if it has dynamic initialization, 0 otherwise.
uptr __has_dynamic_init;
// A pointer to struct that contains source location, could be NULL.
__asan_global_source_location *__location;
}
A destructor function that calls the runtime asan library function
......@@ -2136,19 +2139,20 @@ asan_dynamic_init_call (bool after_p)
const void *__name;
const void *__module_name;
uptr __has_dynamic_init;
__asan_global_source_location *__location;
} type. */
static tree
asan_global_struct (void)
{
static const char *field_names[6]
static const char *field_names[7]
= { "__beg", "__size", "__size_with_redzone",
"__name", "__module_name", "__has_dynamic_init" };
tree fields[6], ret;
"__name", "__module_name", "__has_dynamic_init", "__location"};
tree fields[7], ret;
int i;
ret = make_node (RECORD_TYPE);
for (i = 0; i < 6; i++)
for (i = 0; i < 7; i++)
{
fields[i]
= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
......@@ -2220,6 +2224,8 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
int has_dynamic_init = vnode ? vnode->dynamically_initialized : 0;
CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
build_int_cst (uptr, has_dynamic_init));
CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
build_int_cst (uptr, 0));
init = build_constructor (type, vinner);
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
}
......
......@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
for other FEs by asan.c. */
/* Address Sanitizer */
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v3",
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v4",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
/* Do not reorder the BUILT_IN_ASAN_{REPORT,CHECK}* builtins, e.g. cfgcleanup.c
relies on this order. */
......
2014-09-19 Kostya Serebryany <kcc@google.com>
* All source files: Merge from upstream r218156.
* asan/Makefile.am (asan_files): Added new files.
* asan/Makefile.in: Regenerate.
* ubsan/Makefile.am (ubsan_files): Added new files.
* ubsan/Makefile.in: Regenerate.
* tsan/Makefile.am (tsan_files): Added new files.
* tsan/Makefile.in: Regenerate.
* sanitizer_common/Makefile.am (sanitizer_common_files): Added new
files.
* sanitizer_common/Makefile.in: Regenerate.
* asan/libtool-version: Bump the libasan SONAME.
2014-09-10 Jakub Jelinek <jakub@redhat.com>
* ubsan/ubsan_handlers.cc, ubsan/ubsan_handlers.h: Cherry pick
......
209283
218156
The first line of this file holds the svn revision number of the
last merge done from the master library sources.
......@@ -17,7 +17,7 @@ nodist_toolexeclib_HEADERS = libasan_preinit.o
asan_files = \
asan_activation.cc \
asan_allocator2.cc \
asan_dll_thunk.cc \
asan_debugging.cc \
asan_fake_stack.cc \
asan_globals.cc \
asan_interceptors.cc \
......@@ -34,7 +34,9 @@ asan_files = \
asan_stack.cc \
asan_stats.cc \
asan_thread.cc \
asan_win.cc
asan_win.cc \
asan_win_dll_thunk.cc \
asan_win_dynamic_runtime_thunk.cc
libasan_la_SOURCES = $(asan_files)
libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/lsan/libsanitizer_lsan.la
......
......@@ -89,12 +89,13 @@ libasan_la_DEPENDENCIES = \
$(top_builddir)/lsan/libsanitizer_lsan.la $(am__append_2) \
$(am__append_3) $(am__DEPENDENCIES_1)
am__objects_1 = asan_activation.lo asan_allocator2.lo \
asan_dll_thunk.lo asan_fake_stack.lo asan_globals.lo \
asan_debugging.lo asan_fake_stack.lo asan_globals.lo \
asan_interceptors.lo asan_linux.lo asan_mac.lo \
asan_malloc_linux.lo asan_malloc_mac.lo asan_malloc_win.lo \
asan_new_delete.lo asan_poisoning.lo asan_posix.lo \
asan_report.lo asan_rtl.lo asan_stack.lo asan_stats.lo \
asan_thread.lo asan_win.lo
asan_thread.lo asan_win.lo asan_win_dll_thunk.lo \
asan_win_dynamic_runtime_thunk.lo
am_libasan_la_OBJECTS = $(am__objects_1)
libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
......@@ -275,7 +276,7 @@ nodist_toolexeclib_HEADERS = libasan_preinit.o
asan_files = \
asan_activation.cc \
asan_allocator2.cc \
asan_dll_thunk.cc \
asan_debugging.cc \
asan_fake_stack.cc \
asan_globals.cc \
asan_interceptors.cc \
......@@ -292,7 +293,9 @@ asan_files = \
asan_stack.cc \
asan_stats.cc \
asan_thread.cc \
asan_win.cc
asan_win.cc \
asan_win_dll_thunk.cc \
asan_win_dynamic_runtime_thunk.cc
libasan_la_SOURCES = $(asan_files)
libasan_la_LIBADD = \
......@@ -416,7 +419,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_activation.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator2.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_dll_thunk.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_debugging.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_fake_stack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@
......@@ -434,6 +437,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stats.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dll_thunk.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dynamic_runtime_thunk.Plo@am__quote@
.cc.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
......
......@@ -140,6 +140,8 @@ struct AsanThreadLocalMallocStorage {
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type);
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
void asan_sized_free(void *ptr, uptr size, StackTrace *stack,
AllocType alloc_type);
void *asan_malloc(uptr size, StackTrace *stack);
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
......
......@@ -19,6 +19,7 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
......@@ -165,23 +166,6 @@ struct AsanChunk: ChunkBase {
}
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// If we don't use stack depot, we store the alloc/free stack traces
// in the chunk itself.
u32 *AllocStackBeg() {
return (u32*)(Beg() - RZLog2Size(rz_log));
}
uptr AllocStackSize() {
CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
}
u32 *FreeStackBeg() {
return (u32*)(Beg() + kChunkHeader2Size);
}
uptr FreeStackSize() {
if (user_requested_size < kChunkHeader2Size) return 0;
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
return (available - kChunkHeader2Size) / sizeof(u32);
}
bool AddrIsInside(uptr addr, bool locked_version = false) {
return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
......@@ -461,12 +445,17 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
}
}
static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack,
AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0) return;
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
if (delete_size && flags()->new_delete_type_mismatch &&
delete_size != m->UsedSize()) {
ReportNewDeleteSizeMismatch(p, delete_size, stack);
}
ASAN_FREE_HOOK(ptr);
// Must mark the chunk as quarantined before any changes to its metadata.
AtomicallySetQuarantineFlag(m, ptr, stack);
......@@ -493,7 +482,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
Deallocate(old_ptr, stack, FROM_MALLOC);
Deallocate(old_ptr, 0, stack, FROM_MALLOC);
}
return new_ptr;
}
......@@ -592,7 +581,12 @@ void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
}
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
Deallocate(ptr, stack, alloc_type);
Deallocate(ptr, 0, stack, alloc_type);
}
void asan_sized_free(void *ptr, uptr size, StackTrace *stack,
AllocType alloc_type) {
Deallocate(ptr, size, stack, alloc_type);
}
void *asan_malloc(uptr size, StackTrace *stack) {
......@@ -614,7 +608,7 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) {
if (p == 0)
return Allocate(size, 8, stack, FROM_MALLOC, true);
if (size == 0) {
Deallocate(p, stack, FROM_MALLOC);
Deallocate(p, 0, stack, FROM_MALLOC);
return 0;
}
return Reallocate(p, size, stack);
......@@ -758,23 +752,23 @@ using namespace __asan; // NOLINT
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size". We don't want to expose our redzone sizes, etc here.
uptr __asan_get_estimated_allocated_size(uptr size) {
uptr __sanitizer_get_estimated_allocated_size(uptr size) {
return size;
}
int __asan_get_ownership(const void *p) {
int __sanitizer_get_ownership(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
return (AllocationSize(ptr) > 0);
}
uptr __asan_get_allocated_size(const void *p) {
uptr __sanitizer_get_allocated_size(const void *p) {
if (p == 0) return 0;
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
}
return allocated_size;
}
......@@ -783,12 +777,12 @@ uptr __asan_get_allocated_size(const void *p) {
// Provide default (no-op) implementation of malloc hooks.
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __asan_malloc_hook(void *ptr, uptr size) {
void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __asan_free_hook(void *ptr) {
void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
} // extern "C"
......
//===-- asan_debugging.cc -------------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// This file contains various functions that are generally useful to call when
// using a debugger (LLDB, GDB).
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_flags.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_thread.h"
namespace __asan {
uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
bool alloc_stack) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
if (!chunk.IsValid()) return 0;
StackTrace stack;
if (alloc_stack) {
if (chunk.AllocTid() == kInvalidTid) return 0;
chunk.GetAllocStack(&stack);
if (thread_id) *thread_id = chunk.AllocTid();
} else {
if (chunk.FreeTid() == kInvalidTid) return 0;
chunk.GetFreeStack(&stack);
if (thread_id) *thread_id = chunk.FreeTid();
}
if (trace && size) {
if (size > kStackTraceMax)
size = kStackTraceMax;
if (size > stack.size)
size = stack.size;
for (uptr i = 0; i < size; i++)
trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
return size;
}
return 0;
}
} // namespace __asan
using namespace __asan;
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
}
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
if (shadow_scale)
*shadow_scale = SHADOW_SCALE;
if (shadow_offset)
*shadow_offset = SHADOW_OFFSET;
}
......@@ -50,12 +50,13 @@ struct Flags {
bool print_stats;
bool print_legend;
bool atexit;
bool disable_core;
bool allow_reexec;
bool print_full_thread_history;
bool poison_heap;
bool poison_partial;
bool poison_array_cookie;
bool alloc_dealloc_mismatch;
bool new_delete_type_mismatch;
bool strict_memcmp;
bool strict_init_order;
bool start_deactivated;
......
......@@ -20,6 +20,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __asan {
......@@ -43,6 +44,14 @@ typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
// Lazy-initialized and never deleted.
static VectorOfGlobals *dynamic_init_globals;
// We want to remember where a certain range of globals was registered.
struct GlobalRegistrationSite {
u32 stack_id;
Global *g_first, *g_last;
};
typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
static GlobalRegistrationSiteVector *global_registration_site_vector;
ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
FastPoisonShadow(g->beg, g->size_with_redzone, value);
}
......@@ -61,9 +70,14 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) {
}
static void ReportGlobal(const Global &g, const char *prefix) {
Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
g.module_name, g.has_dynamic_init);
if (g.location) {
Report(" location (%p): name=%s[%p], %d %d\n", g.location,
g.location->filename, g.location->filename, g.location->line_no,
g.location->column_no);
}
}
bool DescribeAddressIfGlobal(uptr addr, uptr size) {
......@@ -79,6 +93,16 @@ bool DescribeAddressIfGlobal(uptr addr, uptr size) {
return res;
}
u32 FindRegistrationSite(const Global *g) {
CHECK(global_registration_site_vector);
for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
if (g >= grs.g_first && g <= grs.g_last)
return grs.stack_id;
}
return 0;
}
// Register a global variable.
// This function may be called more than once for every global
// so we store the globals in a map.
......@@ -99,7 +123,8 @@ static void RegisterGlobal(const Global *g) {
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
if (g->beg == l->g->beg &&
(flags()->detect_odr_violation >= 2 || g->size != l->g->size))
ReportODRViolation(g, l->g);
ReportODRViolation(g, FindRegistrationSite(g),
l->g, FindRegistrationSite(l->g));
}
}
}
......@@ -155,7 +180,18 @@ using namespace __asan; // NOLINT
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
GET_STACK_TRACE_FATAL_HERE;
u32 stack_id = StackDepotPut(stack.trace, stack.size);
BlockingMutexLock lock(&mu_for_globals);
if (!global_registration_site_vector)
global_registration_site_vector =
new(allocator_for_globals) GlobalRegistrationSiteVector(128);
GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
global_registration_site_vector->push_back(site);
if (flags()->report_globals >= 2) {
PRINT_CURRENT_STACK();
Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
}
for (uptr i = 0; i < n; i++) {
RegisterGlobal(&globals[i]);
}
......
//===-- asan_init_version.h -------------------------------------*- C++ -*-===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// This header defines a versioned __asan_init function to be called at the
// startup of the instrumented program.
//===----------------------------------------------------------------------===//
#ifndef ASAN_INIT_VERSION_H
#define ASAN_INIT_VERSION_H
extern "C" {
// Every time the ASan ABI changes we also change the version number in the
// __asan_init function name. Objects built with incompatible ASan ABI
// versions will not link with run-time.
// Changes between ABI versions:
// v1=>v2: added 'module_name' to __asan_global
// v2=>v3: stack frame description (created by the compiler)
// contains the function PC as the 3-rd field (see
// DescribeAddressIfStack).
// v3=>v4: added '__asan_global_source_location' to __asan_global.
#define __asan_init __asan_init_v4
#define __asan_init_name "__asan_init_v4"
}
#endif // ASAN_INIT_VERSION_H
......@@ -144,6 +144,9 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping()
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping()
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
......@@ -291,37 +294,29 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
// intercept mlock and friends.
// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
// All functions return 0 (success).
static void MlockIsUnsupported() {
static bool printed = false;
if (printed) return;
printed = true;
VPrintf(1,
"INFO: AddressSanitizer ignores "
"mlock/mlockall/munlock/munlockall\n");
}
INTERCEPTOR(int, mlock, const void *addr, uptr len) {
MlockIsUnsupported();
return 0;
}
INTERCEPTOR(int, munlock, const void *addr, uptr len) {
MlockIsUnsupported();
return 0;
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
CHECK(REAL(RaiseException));
__asan_handle_no_return();
REAL(RaiseException)(a, b, c, d);
}
INTERCEPTOR(int, mlockall, int flags) {
MlockIsUnsupported();
return 0;
INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
CHECK(REAL(_except_handler3));
__asan_handle_no_return();
return REAL(_except_handler3)(a, b, c, d);
}
INTERCEPTOR(int, munlockall, void) {
MlockIsUnsupported();
return 0;
#if ASAN_DYNAMIC
// This handler is named differently in -MT and -MD CRTs.
#define _except_handler4 _except_handler4_common
#endif
INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
CHECK(REAL(_except_handler4));
__asan_handle_no_return();
return REAL(_except_handler4)(a, b, c, d);
}
#endif
static inline int CharCmp(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
......@@ -523,7 +518,7 @@ INTERCEPTOR(char*, strdup, const char *s) {
}
#endif
INTERCEPTOR(uptr, strlen, const char *s) {
INTERCEPTOR(SIZE_T, strlen, const char *s) {
if (UNLIKELY(!asan_inited)) return internal_strlen(s);
// strlen is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
......@@ -531,15 +526,15 @@ INTERCEPTOR(uptr, strlen, const char *s) {
return REAL(strlen)(s);
}
ENSURE_ASAN_INITED();
uptr length = REAL(strlen)(s);
SIZE_T length = REAL(strlen)(s);
if (flags()->replace_str) {
ASAN_READ_RANGE(s, length + 1);
}
return length;
}
INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
uptr length = REAL(wcslen)(s);
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
SIZE_T length = REAL(wcslen)(s);
if (!asan_init_is_running) {
ENSURE_ASAN_INITED();
ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
......@@ -691,6 +686,16 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
#if ASAN_INTERCEPT_FORK
INTERCEPTOR(int, fork, void) {
ENSURE_ASAN_INITED();
if (common_flags()->coverage) CovBeforeFork();
int pid = REAL(fork)();
if (common_flags()->coverage) CovAfterFork(pid);
return pid;
}
#endif // ASAN_INTERCEPT_FORK
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
......@@ -712,6 +717,9 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
namespace __asan {
void InitializeWindowsInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
ASAN_INTERCEPT_FUNC(RaiseException);
ASAN_INTERCEPT_FUNC(_except_handler3);
ASAN_INTERCEPT_FUNC(_except_handler4);
}
} // namespace __asan
......@@ -759,14 +767,6 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strtoll);
#endif
#if ASAN_INTERCEPT_MLOCKX
// Intercept mlock/munlock.
ASAN_INTERCEPT_FUNC(mlock);
ASAN_INTERCEPT_FUNC(munlock);
ASAN_INTERCEPT_FUNC(mlockall);
ASAN_INTERCEPT_FUNC(munlockall);
#endif
// Intecept signal- and jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
......@@ -789,7 +789,7 @@ void InitializeAsanInterceptors() {
// Intercept exception handling functions.
#if ASAN_INTERCEPT___CXA_THROW
INTERCEPT_FUNCTION(__cxa_throw);
ASAN_INTERCEPT_FUNC(__cxa_throw);
#endif
// Intercept threading-related functions
......@@ -802,6 +802,10 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
#if ASAN_INTERCEPT_FORK
ASAN_INTERCEPT_FUNC(fork);
#endif
// Some Windows-specific interceptors.
#if SANITIZER_WINDOWS
InitializeWindowsInterceptors();
......
......@@ -24,14 +24,14 @@
# define ASAN_INTERCEPT_STRDUP 1
# define ASAN_INTERCEPT_INDEX 1
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
# define ASAN_INTERCEPT_MLOCKX 1
# define ASAN_INTERCEPT_FORK 1
#else
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
# define ASAN_INTERCEPT__LONGJMP 0
# define ASAN_INTERCEPT_STRDUP 0
# define ASAN_INTERCEPT_INDEX 0
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
# define ASAN_INTERCEPT_MLOCKX 0
# define ASAN_INTERCEPT_FORK 0
#endif
#if SANITIZER_FREEBSD || SANITIZER_LINUX
......@@ -64,7 +64,9 @@
# define ASAN_INTERCEPT_SIGLONGJMP 0
#endif
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
// Android bug: https://code.google.com/p/android/issues/detail?id=61799
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
!(SANITIZER_ANDROID && defined(__i386))
# define ASAN_INTERCEPT___CXA_THROW 1
#else
# define ASAN_INTERCEPT___CXA_THROW 0
......@@ -80,7 +82,7 @@ DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(uptr, strlen, const char *s)
DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
......
......@@ -15,21 +15,24 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "asan_init_version.h"
using __sanitizer::uptr;
extern "C" {
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
// Every time the asan ABI changes we also change the version number in this
// name. Objects build with incompatible asan ABI version
// will not link with run-time.
// Changes between ABI versions:
// v1=>v2: added 'module_name' to __asan_global
// v2=>v3: stack frame description (created by the compiler)
// contains the function PC as the 3-rd field (see
// DescribeAddressIfStack).
SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
#define __asan_init __asan_init_v3
// Please note that __asan_init is a macro that is replaced with
// __asan_init_vXXX at compile-time.
SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
// This structure is used to describe the source location of a place where
// global was defined.
struct __asan_global_source_location {
const char *filename;
int line_no;
int column_no;
};
// This structure describes an instrumented global variable.
struct __asan_global {
......@@ -40,6 +43,8 @@ extern "C" {
const char *module_name; // Module name as a C string. This pointer is a
// unique identifier of a module.
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
__asan_global_source_location *location; // Source location of a global,
// or NULL if it is unknown.
};
// These two functions should be called by the instrumented code.
......@@ -84,6 +89,17 @@ extern "C" {
void __asan_describe_address(uptr addr);
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
u32 *thread_id);
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
u32 *thread_id);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_report_error(uptr pc, uptr bp, uptr sp,
uptr addr, int is_write, uptr access_size);
......@@ -97,25 +113,11 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_on_error();
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_estimated_allocated_size(uptr size);
SANITIZER_INTERFACE_ATTRIBUTE int __asan_get_ownership(const void *p);
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __asan_default_options();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __asan_free_hook(void *ptr);
// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
SANITIZER_INTERFACE_ATTRIBUTE
extern int __asan_option_detect_stack_use_after_return;
......@@ -142,6 +144,11 @@ extern "C" {
void* __asan_memset(void *s, int c, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void* __asan_memmove(void* dest, const void* src, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_poison_cxx_array_cookie(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_load_cxx_array_cookie(uptr *p);
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H
......@@ -43,10 +43,6 @@
# endif
#endif
#ifndef ASAN_USE_PREINIT_ARRAY
# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
#endif
#ifndef ASAN_DYNAMIC
# ifdef PIC
# define ASAN_DYNAMIC 1
......@@ -96,6 +92,8 @@ void AppendToErrorMessageBuffer(const char *buffer);
void ParseExtraActivationFlags();
void *AsanDlSymNext(const char *sym);
// Platform-specific options.
#if SANITIZER_MAC
bool PlatformHasDifferentMemcpyAndMemmove();
......@@ -108,9 +106,9 @@ bool PlatformHasDifferentMemcpyAndMemmove();
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size)
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
#define ASAN_FREE_HOOK(ptr) \
if (&__asan_free_hook) __asan_free_hook(ptr)
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
#define ASAN_ON_ERROR() \
if (&__asan_on_error) __asan_on_error()
......@@ -134,6 +132,7 @@ const int kAsanContiguousContainerOOBMagic = 0xfc;
const int kAsanStackUseAfterScopeMagic = 0xf8;
const int kAsanGlobalRedzoneMagic = 0xf9;
const int kAsanInternalHeapMagic = 0xfe;
const int kAsanArrayCookieMagic = 0xac;
static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
static const uptr kRetiredStackFrameMagic = 0x45E0360E;
......
......@@ -17,6 +17,7 @@
#include "asan_internal.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_freebsd.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
......@@ -25,6 +26,7 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
......@@ -40,19 +42,14 @@
extern "C" void* _DYNAMIC;
#else
#include <sys/ucontext.h>
#include <dlfcn.h>
#include <link.h>
#endif
// x86_64 FreeBSD 9.2 and older define 64-bit register names in both 64-bit
// and 32-bit modes.
#if SANITIZER_FREEBSD
#include <sys/param.h>
# if __FreeBSD_version <= 902001 // v9.2
# define mc_eip mc_rip
# define mc_ebp mc_rbp
# define mc_esp mc_rsp
# endif
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
// 32-bit mode.
#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
__FreeBSD_version <= 902001 // v9.2
#define ucontext_t xucontext_t
#endif
typedef enum {
......@@ -241,6 +238,10 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
}
#endif
void *AsanDlSymNext(const char *sym) {
return dlsym(RTLD_NEXT, sym);
}
} // namespace __asan
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
......@@ -372,32 +372,44 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
work(); \
}
// Forces the compiler to generate a frame pointer in the function.
#define ENABLE_FRAME_POINTER \
do { \
volatile uptr enable_fp; \
enable_fp = GET_CURRENT_FRAME(); \
} while (0)
INTERCEPTOR(void, dispatch_async,
dispatch_queue_t dq, void(^work)(void)) {
ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_async)(dq, asan_block);
}
INTERCEPTOR(void, dispatch_group_async,
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_group_async)(dg, dq, asan_block);
}
INTERCEPTOR(void, dispatch_after,
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_after)(when, queue, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
dispatch_source_t ds, void(^work)(void)) {
ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
}
INTERCEPTOR(void, dispatch_source_set_event_handler,
dispatch_source_t ds, void(^work)(void)) {
ENABLE_FRAME_POINTER;
GET_ASAN_BLOCK(work);
REAL(dispatch_source_set_event_handler)(ds, asan_block);
}
......
......@@ -21,41 +21,6 @@
#include "asan_internal.h"
#include "asan_stack.h"
#if SANITIZER_ANDROID
DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
struct MallocDebug {
void* (*malloc)(uptr bytes);
void (*free)(void* mem);
void* (*calloc)(uptr n_elements, uptr elem_size);
void* (*realloc)(void* oldMem, uptr bytes);
void* (*memalign)(uptr alignment, uptr bytes);
};
const MallocDebug asan_malloc_dispatch ALIGNED(32) = {
WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign)
};
extern "C" const MallocDebug* __libc_malloc_dispatch;
namespace __asan {
void ReplaceSystemMalloc() {
__libc_malloc_dispatch = &asan_malloc_dispatch;
}
} // namespace __asan
#else // ANDROID
namespace __asan {
void ReplaceSystemMalloc() {
}
} // namespace __asan
#endif // ANDROID
// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
......@@ -100,6 +65,11 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
......@@ -151,4 +121,64 @@ INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats();
}
#if SANITIZER_ANDROID
// Format of __libc_malloc_dispatch has changed in Android L.
// While we are moving towards a solution that does not depend on bionic
// internals, here is something to support both K* and L releases.
struct MallocDebugK {
void *(*malloc)(uptr bytes);
void (*free)(void *mem);
void *(*calloc)(uptr n_elements, uptr elem_size);
void *(*realloc)(void *oldMem, uptr bytes);
void *(*memalign)(uptr alignment, uptr bytes);
uptr (*malloc_usable_size)(void *mem);
};
struct MallocDebugL {
void *(*calloc)(uptr n_elements, uptr elem_size);
void (*free)(void *mem);
fake_mallinfo (*mallinfo)(void);
void *(*malloc)(uptr bytes);
uptr (*malloc_usable_size)(void *mem);
void *(*memalign)(uptr alignment, uptr bytes);
int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
void* (*pvalloc)(uptr size);
void *(*realloc)(void *oldMem, uptr bytes);
void* (*valloc)(uptr size);
};
ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
WRAP(malloc), WRAP(free), WRAP(calloc),
WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
WRAP(calloc), WRAP(free), WRAP(mallinfo),
WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
WRAP(valloc)};
namespace __asan {
void ReplaceSystemMalloc() {
void **__libc_malloc_dispatch_p =
(void **)AsanDlSymNext("__libc_malloc_dispatch");
if (__libc_malloc_dispatch_p) {
// Decide on K vs L dispatch format by the presence of
// __libc_malloc_default_dispatch export in libc.
void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
if (default_dispatch_p)
*__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
else
*__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
}
}
} // namespace __asan
#else // SANITIZER_ANDROID
namespace __asan {
void ReplaceSystemMalloc() {
}
} // namespace __asan
#endif // SANITIZER_ANDROID
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
......@@ -21,71 +21,77 @@
#include <stddef.h>
// ---------------------- Replacement functions ---------------- {{{1
using namespace __asan; // NOLINT
// FIXME: Simply defining functions with the same signature in *.obj
// files overrides the standard functions in *.lib
// This works well for simple helloworld-like tests but might need to be
// revisited in the future.
// MT: Simply defining functions with the same signature in *.obj
// files overrides the standard functions in the CRT.
// MD: Memory allocation functions are defined in the CRT .dll,
// so we have to intercept them before they are called for the first time.
#if ASAN_DYNAMIC
# define ALLOCATION_FUNCTION_ATTRIBUTE
#else
# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
#endif
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void free(void *ptr) {
GET_STACK_TRACE_FREE;
return asan_free(ptr, &stack, FROM_MALLOC);
}
SANITIZER_INTERFACE_ATTRIBUTE
void _free_dbg(void* ptr, int) {
ALLOCATION_FUNCTION_ATTRIBUTE
void _free_dbg(void *ptr, int) {
free(ptr);
}
ALLOCATION_FUNCTION_ATTRIBUTE
void cfree(void *ptr) {
CHECK(!"cfree() should not be used on Windows?");
CHECK(!"cfree() should not be used on Windows");
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *malloc(size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
SANITIZER_INTERFACE_ATTRIBUTE
void* _malloc_dbg(size_t size, int , const char*, int) {
ALLOCATION_FUNCTION_ATTRIBUTE
void *_malloc_dbg(size_t size, int, const char *, int) {
return malloc(size);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *calloc(size_t nmemb, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
SANITIZER_INTERFACE_ATTRIBUTE
void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
return calloc(n, size);
ALLOCATION_FUNCTION_ATTRIBUTE
void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
return calloc(nmemb, size);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
return calloc(nmemb, size);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *realloc(void *ptr, size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *_realloc_dbg(void *ptr, size_t size, int) {
CHECK(!"_realloc_dbg should not exist!");
return 0;
}
SANITIZER_INTERFACE_ATTRIBUTE
void* _recalloc(void* p, size_t n, size_t elem_size) {
ALLOCATION_FUNCTION_ATTRIBUTE
void *_recalloc(void *p, size_t n, size_t elem_size) {
if (!p)
return calloc(n, elem_size);
const size_t size = n * elem_size;
......@@ -94,23 +100,23 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
return realloc(p, size);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
size_t _msize(void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return asan_malloc_usable_size(ptr, pc, bp);
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *_expand(void *memblock, size_t size) {
// _expand is used in realloc-like functions to resize the buffer if possible.
// We don't want memory to stand still while resizing buffers, so return 0.
return 0;
}
SANITIZER_INTERFACE_ATTRIBUTE
ALLOCATION_FUNCTION_ATTRIBUTE
void *_expand_dbg(void *memblock, size_t size) {
return 0;
return _expand(memblock, size);
}
// TODO(timurrrr): Might want to add support for _aligned_* allocation
......@@ -131,37 +137,38 @@ int _CrtSetReportMode(int, int) {
}
} // extern "C"
using __interception::GetRealFunctionAddress;
// We don't want to include "windows.h" in this file to avoid extra attributes
// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
DWORD prot, DWORD *old_prot);
const int PAGE_EXECUTE_READWRITE = 0x40;
namespace __asan {
void ReplaceSystemMalloc() {
#if defined(_DLL)
# ifdef _WIN64
# error ReplaceSystemMalloc was not tested on x64
# endif
char *crt_malloc;
if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
// Replace malloc in the CRT dll with a jump to our malloc.
DWORD old_prot, unused;
CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case.
ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
crt_malloc[0] = 0xE9; // jmp, should be followed by an offset.
REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
// FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
}
// FIXME: investigate whether anything else is needed.
#if defined(ASAN_DYNAMIC)
// We don't check the result because CRT might not be used in the process.
__interception::OverrideFunction("free", (uptr)free);
__interception::OverrideFunction("malloc", (uptr)malloc);
__interception::OverrideFunction("_malloc_crt", (uptr)malloc);
__interception::OverrideFunction("calloc", (uptr)calloc);
__interception::OverrideFunction("_calloc_crt", (uptr)calloc);
__interception::OverrideFunction("realloc", (uptr)realloc);
__interception::OverrideFunction("_realloc_crt", (uptr)realloc);
__interception::OverrideFunction("_recalloc", (uptr)_recalloc);
__interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
__interception::OverrideFunction("_msize", (uptr)_msize);
__interception::OverrideFunction("_expand", (uptr)_expand);
// Override different versions of 'operator new' and 'operator delete'.
// No need to override the nothrow versions as they just wrap the throw
// versions.
// FIXME: Unfortunately, MSVC miscompiles the statements that take the
// addresses of the array versions of these operators,
// see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
// We might want to try to work around this by [inline] assembly or compiling
// parts of the RTL with Clang.
void *(*op_new)(size_t sz) = operator new;
void (*op_delete)(void *p) = operator delete;
void *(*op_array_new)(size_t sz) = operator new[];
void (*op_array_delete)(void *p) = operator delete[];
__interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
__interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
__interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
__interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
#endif
}
} // namespace __asan
......
......@@ -18,6 +18,13 @@
#include <stddef.h>
// C++ operators can't have visibility attributes on Windows.
#if SANITIZER_WINDOWS
# define CXX_OPERATOR_ATTRIBUTE
#else
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
#endif
using namespace __asan; // NOLINT
// This code has issues on OSX.
......@@ -49,14 +56,14 @@ struct nothrow_t {};
#endif // __FreeBSD_version
#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW); }
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
......@@ -80,22 +87,32 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
asan_free(ptr, &stack, type);
#if !SANITIZER_MAC
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void operator delete(void *ptr) throw() {
OPERATOR_DELETE_BODY(FROM_NEW);
}
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void operator delete[](void *ptr) throw() {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW);
}
INTERCEPTOR_ATTRIBUTE
CXX_OPERATOR_ATTRIBUTE
void operator delete[](void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
CXX_OPERATOR_ATTRIBUTE
void operator delete(void *ptr, size_t size) throw() {
GET_STACK_TRACE_FREE;
asan_sized_free(ptr, size, &stack, FROM_NEW);
}
CXX_OPERATOR_ATTRIBUTE
void operator delete[](void *ptr, size_t size) throw() {
GET_STACK_TRACE_FREE;
asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
}
#else // SANITIZER_MAC
INTERCEPTOR(void, _ZdlPv, void *ptr) {
......
......@@ -225,6 +225,35 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __asan_poison_cxx_array_cookie(uptr p) {
if (SANITIZER_WORDSIZE != 64) return;
if (!flags()->poison_array_cookie) return;
uptr s = MEM_TO_SHADOW(p);
*reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_load_cxx_array_cookie(uptr *p) {
if (SANITIZER_WORDSIZE != 64) return *p;
if (!flags()->poison_array_cookie) return *p;
uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
u8 sval = *reinterpret_cast<u8*>(s);
if (sval == kAsanArrayCookieMagic) return *p;
// If sval is not kAsanArrayCookieMagic it can only be freed memory,
// which means that we are going to get double-free. So, return 0 to avoid
// infinite loop of destructors. We don't want to report a double-free here
// though, so print a warning just in case.
// CHECK_EQ(sval, kAsanHeapFreeMagic);
if (sval == kAsanHeapFreeMagic) {
Report("AddressSanitizer: loaded array cookie from free-d memory; "
"expect a double-free report\n");
return 0;
}
// FIXME: apparently it can be something else; need to find a reproducer.
return *p;
}
// This is a simplified version of __asan_(un)poison_memory_region, which
// assumes that left border of region to be poisoned is properly aligned.
static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
......
......@@ -33,7 +33,6 @@ void PoisonShadowPartialRightRedzone(uptr addr,
ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
u8 value) {
DCHECK(flags()->poison_heap);
uptr PageSize = GetPageSizeCached();
uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
uptr shadow_end = MEM_TO_SHADOW(
aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
......@@ -46,8 +45,9 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else {
uptr page_beg = RoundUpTo(shadow_beg, PageSize);
uptr page_end = RoundDownTo(shadow_end, PageSize);
uptr page_size = GetPageSizeCached();
uptr page_beg = RoundUpTo(shadow_beg, page_size);
uptr page_end = RoundDownTo(shadow_end, page_size);
if (page_beg >= page_end) {
REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
......
......@@ -48,7 +48,7 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
(code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(pc, sp, bp, context, addr);
else
ReportSIGSEGV(pc, sp, bp, context, addr);
ReportSIGSEGV("SEGV", pc, sp, bp, context, addr);
}
// ---------------------- TSD ---------------- {{{1
......
......@@ -8,22 +8,12 @@
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Call __asan_init at the very early stage of process startup.
// On Linux we use .preinit_array section (unless PIC macro is defined).
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
// On Linux, we force __asan_init to be called before anyone else
// by placing it into .preinit_array section.
// FIXME: do we have anything like this on Mac?
#if SANITIZER_CAN_USE_PREINIT_ARRAY
// The symbol is called __local_asan_preinit, because it's not intended to be
// exported.
__attribute__((section(".preinit_array"), used))
void (*__local_asan_preinit)(void) = __asan_init;
#elif SANITIZER_WINDOWS && defined(_DLL)
// On Windows, when using dynamic CRT (/MD), we can put a pointer
// to __asan_init into the global list of C initializers.
// See crt0dat.c in the CRT sources for the details.
#pragma section(".CRT$XIB", long, read) // NOLINT
__declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
#endif
......@@ -16,6 +16,13 @@
namespace __asan {
struct StackVarDescr {
uptr beg;
uptr size;
const char *name_pos;
uptr name_len;
};
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
void DescribeHeapAddress(uptr addr, uptr access_size);
......@@ -23,6 +30,8 @@ bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
const __asan_global &g);
bool DescribeAddressIfShadow(uptr addr);
bool ParseFrameDescription(const char *frame_descr,
InternalMmapVector<StackVarDescr> *vars);
bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
void DescribeAddress(uptr addr, uptr access_size);
......@@ -32,8 +41,10 @@ void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void NORETURN
ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
void NORETURN
ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
void *context, uptr addr);
void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
StackTrace *free_stack);
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
......@@ -41,8 +52,8 @@ void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType dealloc_type);
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
StackTrace *stack);
void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr,
StackTrace *stack);
void NORETURN
ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack);
void NORETURN ReportStringFunctionMemoryRangesOverlap(
const char *function, const char *offset1, uptr length1,
const char *offset2, uptr length2, StackTrace *stack);
......@@ -53,7 +64,8 @@ ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid,
uptr new_mid, StackTrace *stack);
void NORETURN
ReportODRViolation(const __asan_global *g1, const __asan_global *g2);
ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2);
// Mac-specific errors and warnings.
void WarnMacFreeUnallocated(
......
......@@ -171,11 +171,6 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
"If set, prints ASan exit stats even after program terminates "
"successfully.");
ParseFlag(str, &f->disable_core, "disable_core",
"Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
"dumping a 16T+ core file. "
"Ignored on OSes that don't dump core by default.");
ParseFlag(str, &f->allow_reexec, "allow_reexec",
"Allow the tool to re-exec the program. This may interfere badly with "
"the debugger.");
......@@ -189,6 +184,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
"Poison (or not) the heap memory on [de]allocation. Zero value is useful "
"for benchmarking the allocator or instrumentator.");
ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie",
"Poison (or not) the array cookie after operator new[].");
ParseFlag(str, &f->poison_partial, "poison_partial",
"If true, poison partially addressable 8-byte aligned words "
"(default=true). This flag affects heap and global buffers, but not "
......@@ -196,6 +194,10 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch",
"Report errors on malloc/delete, new/free, new/delete[], etc.");
ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch",
"Report errors on mismatch betwen size of new and delete.");
ParseFlag(str, &f->strict_memcmp, "strict_memcmp",
"If true, assume that memcmp(p1, p2, n) always reads n bytes before "
"comparing p1 and p2.");
......@@ -262,21 +264,23 @@ void InitializeFlags(Flags *f, const char *env) {
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
f->disable_core = (SANITIZER_WORDSIZE == 64);
f->allow_reexec = true;
f->print_full_thread_history = true;
f->poison_heap = true;
f->poison_array_cookie = true;
f->poison_partial = true;
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
// https://code.google.com/p/address-sanitizer/issues/detail?id=131
// https://code.google.com/p/address-sanitizer/issues/detail?id=309
// TODO(glider,timurrrr): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
f->new_delete_type_mismatch = true;
f->strict_memcmp = true;
f->strict_init_order = false;
f->start_deactivated = false;
f->detect_invalid_pointer_pairs = 0;
f->detect_container_overflow = true;
f->detect_odr_violation = 2;
// Override from compile definition.
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
......@@ -456,13 +460,6 @@ static NOINLINE void force_interface_symbols() {
case 15: __asan_set_error_report_callback(0); break;
case 16: __asan_handle_no_return(); break;
case 17: __asan_address_is_poisoned(0); break;
case 18: __asan_get_allocated_size(0); break;
case 19: __asan_get_current_allocated_bytes(); break;
case 20: __asan_get_estimated_allocated_size(0); break;
case 21: __asan_get_free_bytes(); break;
case 22: __asan_get_heap_size(); break;
case 23: __asan_get_ownership(0); break;
case 24: __asan_get_unmapped_bytes(); break;
case 25: __asan_poison_memory_region(0, 0); break;
case 26: __asan_unpoison_memory_region(0, 0); break;
case 27: __asan_set_error_exit_code(0); break;
......@@ -593,6 +590,11 @@ static void AsanInitInternal() {
InitializeAsanInterceptors();
// Enable system log ("adb logcat") on Android.
// Doing this before interceptors are initialized crashes in:
// AsanInitInternal -> android_log_write -> __interceptor_strcmp
AndroidLogInit();
ReplaceSystemMalloc();
uptr shadow_start = kLowShadowBeg;
......@@ -601,7 +603,8 @@ static void AsanInitInternal() {
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
!ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
......@@ -611,9 +614,7 @@ static void AsanInitInternal() {
if (common_flags()->verbosity)
PrintAddressSpaceLayout();
if (flags()->disable_core) {
DisableCoreDumper();
}
DisableCoreDumperIfNecessary();
if (full_shadow_is_available) {
// mmap the low shadow plus at least one page at the left.
......@@ -648,12 +649,8 @@ static void AsanInitInternal() {
AsanTSDInit(PlatformTSDDtor);
InstallDeadlySignalHandlers(AsanOnSIGSEGV);
// Allocator should be initialized before starting external symbolizer, as
// fork() on Mac locks the allocator.
InitializeAllocator();
Symbolizer::Init(common_flags()->external_symbolizer_path);
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
asan_inited = 1;
......@@ -682,7 +679,7 @@ static void AsanInitInternal() {
SanitizerInitializeUnwinder();
#if CAN_SANITIZE_LEAKS
__lsan::InitCommonLsan();
__lsan::InitCommonLsan(false);
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
Atexit(__lsan::DoLeakCheck);
}
......
......@@ -13,6 +13,7 @@
#include "asan_internal.h"
#include "asan_stats.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
......@@ -127,8 +128,8 @@ static void PrintAccumulatedStats() {
BlockingMutexLock lock(&print_lock);
stats.Print();
StackDepotStats *stack_depot_stats = StackDepotGetStats();
Printf("Stats: StackDepot: %zd ids; %zdM mapped\n",
stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20);
Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
PrintInternalAllocatorStats();
}
......@@ -137,7 +138,7 @@ static void PrintAccumulatedStats() {
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
uptr __asan_get_current_allocated_bytes() {
uptr __sanitizer_get_current_allocated_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr malloced = stats.malloced;
......@@ -147,13 +148,13 @@ uptr __asan_get_current_allocated_bytes() {
return (malloced > freed) ? malloced - freed : 1;
}
uptr __asan_get_heap_size() {
uptr __sanitizer_get_heap_size() {
AsanStats stats;
GetAccumulatedStats(&stats);
return stats.mmaped - stats.munmaped;
}
uptr __asan_get_free_bytes() {
uptr __sanitizer_get_free_bytes() {
AsanStats stats;
GetAccumulatedStats(&stats);
uptr total_free = stats.mmaped
......@@ -167,7 +168,7 @@ uptr __asan_get_free_bytes() {
return (total_free > total_used) ? total_free - total_used : 1;
}
uptr __asan_get_unmapped_bytes() {
uptr __sanitizer_get_unmapped_bytes() {
return 0;
}
......
......@@ -139,7 +139,10 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
}
void AsanThread::Init() {
fake_stack_ = 0; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls();
CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
ClearShadowForThreadStackAndTLS();
......@@ -147,7 +150,6 @@ void AsanThread::Init() {
VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
(void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
&local);
fake_stack_ = 0; // Will be initialized lazily if needed.
AsanPlatformThreadInit();
}
......
......@@ -19,6 +19,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_report.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
......@@ -68,7 +69,7 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); }
void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
......@@ -84,6 +85,67 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
UNIMPLEMENTED();
}
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
CONTEXT *context = info->ContextRecord;
uptr pc = (uptr)exception_record->ExceptionAddress;
#ifdef _WIN64
uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
#else
uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
#endif
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
const char *description =
(exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
? "access-violation"
: "in-page-error";
uptr access_addr = exception_record->ExceptionInformation[1];
ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
}
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
return default_seh_handler(info);
}
// We want to install our own exception handler (EH) to print helpful reports
// on access violations and whatnot. Unfortunately, the CRT initializers assume
// they are run before any user code and drop any previously-installed EHs on
// the floor, so we can't install our handler inside __asan_init.
// (See crt0dat.c in the CRT sources for the details)
//
// Things get even more complicated with the dynamic runtime, as it finishes its
// initialization before the .exe module CRT begins to initialize.
//
// For the static runtime (-MT), it's enough to put a callback to
// __asan_set_seh_filter in the last section for C initializers.
//
// For the dynamic runtime (-MD), we want link the same
// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
// will be called for each instrumented module. This ensures that at least one
// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int __asan_set_seh_filter() {
// We should only store the previous handler if it's not our own handler in
// order to avoid loops in the EH chain.
auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
if (prev_seh_handler != &SEHHandler)
default_seh_handler = prev_seh_handler;
return 0;
}
#if !ASAN_DYNAMIC
// Put a pointer to __asan_set_seh_filter at the end of the global list
// of C initializers, after the default EH is set by the CRT.
#pragma section(".CRT$XIZ", long, read) // NOLINT
static __declspec(allocate(".CRT$XIZ"))
int (*__intercept_seh)() = __asan_set_seh_filter;
#endif
} // namespace __asan
#endif // _WIN32
//===-- asan_win_uar_thunk.cc ---------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// This file defines things that need to be present in the application modules
// to interact with the ASan DLL runtime correctly and can't be implemented
// using the default "import library" generated when linking the DLL RTL.
//
// This includes:
// - forwarding the detect_stack_use_after_return runtime option
// - installing a custom SEH handler
//
//===----------------------------------------------------------------------===//
// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
extern "C" {
__declspec(dllimport) int __asan_set_seh_filter();
__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
// Define a copy of __asan_option_detect_stack_use_after_return that should be
// used when linking an MD runtime with a set of object files on Windows.
//
// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
// so normally we would just dllimport it. Unfortunately, the dllimport
// attribute adds __imp_ prefix to the symbol name of a variable.
// Since in general we don't know if a given TU is going to be used
// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
// just to work around this issue, let's clone the a variable that is
// constant after initialization anyways.
int __asan_option_detect_stack_use_after_return =
__asan_should_detect_stack_use_after_return();
// Set the ASan-specific SEH handler at the end of CRT initialization of each
// module (see asan_win.cc for the details).
//
// Unfortunately, putting a pointer to __asan_set_seh_filter into
// __asan_intercept_seh gets optimized out, so we have to use an extra function.
static int SetSEHFilter() { return __asan_set_seh_filter(); }
#pragma section(".CRT$XIZ", long, read) // NOLINT
__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
}
#endif // ASAN_DYNAMIC_RUNTIME_THUNK
......@@ -3,4 +3,4 @@
# a separate file so that version updates don't involve re-running
# automake.
# CURRENT:REVISION:AGE
1:0:0
2:0:0
//===-- allocator_interface.h ---------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Public interface header for allocator used in sanitizers (ASan/TSan/MSan).
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
#define SANITIZER_ALLOCATOR_INTERFACE_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Returns the estimated number of bytes that will be reserved by allocator
for request of "size" bytes. If allocator can't allocate that much
memory, returns the maximal possible allocation size, otherwise returns
"size". */
size_t __sanitizer_get_estimated_allocated_size(size_t size);
/* Returns true if p was returned by the allocator and
is not yet freed. */
int __sanitizer_get_ownership(const volatile void *p);
/* Returns the number of bytes reserved for the pointer p.
Requires (get_ownership(p) == true) or (p == 0). */
size_t __sanitizer_get_allocated_size(const volatile void *p);
/* Number of bytes, allocated and not yet freed by the application. */
size_t __sanitizer_get_current_allocated_bytes();
/* Number of bytes, mmaped by the allocator to fulfill allocation requests.
Generally, for request of X bytes, allocator can reserve and add to free
lists a large number of chunks of size X to use them for future requests.
All these chunks count toward the heap size. Currently, allocator never
releases memory to OS (instead, it just puts freed chunks to free
lists). */
size_t __sanitizer_get_heap_size();
/* Number of bytes, mmaped by the allocator, which can be used to fulfill
allocation requests. When a user program frees memory chunk, it can first
fall into quarantine and will count toward __sanitizer_get_free_bytes()
later. */
size_t __sanitizer_get_free_bytes();
/* Number of bytes in unmapped pages, that are released to OS. Currently,
always returns 0. */
size_t __sanitizer_get_unmapped_bytes();
/* Malloc hooks that may be optionally provided by user.
__sanitizer_malloc_hook(ptr, size) is called immediately after
allocation of "size" bytes, which returned "ptr".
__sanitizer_free_hook(ptr) is called immediately before
deallocation of "ptr". */
void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
void __sanitizer_free_hook(const volatile void *ptr);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
......@@ -60,6 +60,22 @@ extern "C" {
// Print the description of addr (useful when debugging in gdb).
void __asan_describe_address(void *addr);
// Useful for calling from the debugger to get the allocation stack trace
// and thread ID for a heap address. Stores up to 'size' frames into 'trace',
// returns the number of stored frames or 0 on error.
size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
int *thread_id);
// Useful for calling from the debugger to get the free stack trace
// and thread ID for a heap address. Stores up to 'size' frames into 'trace',
// returns the number of stored frames or 0 on error.
size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
int *thread_id);
// Useful for calling from the debugger to get the current shadow memory
// mapping.
void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
// This is an internal function that is called to report an error.
// However it is still a part of the interface because users may want to
// set a breakpoint on this function in a debugger.
......@@ -81,32 +97,6 @@ extern "C" {
// the program crashes before ASan report is printed.
void __asan_on_error();
// Returns the estimated number of bytes that will be reserved by allocator
// for request of "size" bytes. If ASan allocator can't allocate that much
// memory, returns the maximal possible allocation size, otherwise returns
// "size".
size_t __asan_get_estimated_allocated_size(size_t size);
// Returns 1 if p was returned by the ASan allocator and is not yet freed.
// Otherwise returns 0.
int __asan_get_ownership(const void *p);
// Returns the number of bytes reserved for the pointer p.
// Requires (get_ownership(p) == true) or (p == 0).
size_t __asan_get_allocated_size(const void *p);
// Number of bytes, allocated and not yet freed by the application.
size_t __asan_get_current_allocated_bytes();
// Number of bytes, mmaped by asan allocator to fulfill allocation requests.
// Generally, for request of X bytes, allocator can reserve and add to free
// lists a large number of chunks of size X to use them for future requests.
// All these chunks count toward the heap size. Currently, allocator never
// releases memory to OS (instead, it just puts freed chunks to free lists).
size_t __asan_get_heap_size();
// Number of bytes, mmaped by asan allocator, which can be used to fulfill
// allocation requests. When a user program frees memory chunk, it can first
// fall into quarantine and will count toward __asan_get_free_bytes() later.
size_t __asan_get_free_bytes();
// Number of bytes in unmapped pages, that are released to OS. Currently,
// always returns 0.
size_t __asan_get_unmapped_bytes();
// Prints accumulated stats to stderr. Used for debugging.
void __asan_print_accumulated_stats();
......@@ -114,14 +104,6 @@ extern "C" {
// a string containing ASan runtime options. See asan_flags.h for details.
const char* __asan_default_options();
// Malloc hooks that may be optionally provided by user.
// __asan_malloc_hook(ptr, size) is called immediately after
// allocation of "size" bytes, which returned "ptr".
// __asan_free_hook(ptr) is called immediately before
// deallocation of "ptr".
void __asan_malloc_hook(void *ptr, size_t size);
void __asan_free_hook(void *ptr);
// The following 2 functions facilitate garbage collection in presence of
// asan's fake stack.
......
......@@ -64,6 +64,10 @@ extern "C" {
void __sanitizer_cov_init();
// Record and dump coverage info.
void __sanitizer_cov_dump();
// Open <name>.sancov.packed in the coverage directory and return the file
// 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);
// Annotate the current state of a contiguous container, such as
// std::vector, std::string or similar.
......
......@@ -17,10 +17,6 @@
#ifdef __cplusplus
extern "C" {
#endif
/* Returns a string describing a stack origin.
Return NULL if the origin is invalid, or is not a stack origin. */
const char *__msan_get_origin_descr_if_stack(uint32_t id);
/* Set raw origin for the memory range. */
void __msan_set_origin(const volatile void *a, size_t size, uint32_t origin);
......@@ -91,55 +87,10 @@ extern "C" {
a string containing Msan runtime options. See msan_flags.h for details. */
const char* __msan_default_options();
// Sets the callback to be called right before death on error.
// Passing 0 will unset the callback.
/* Sets the callback to be called right before death on error.
Passing 0 will unset the callback. */
void __msan_set_death_callback(void (*callback)(void));
/***********************************/
/* Allocator statistics interface. */
/* Returns the estimated number of bytes that will be reserved by allocator
for request of "size" bytes. If Msan allocator can't allocate that much
memory, returns the maximal possible allocation size, otherwise returns
"size". */
size_t __msan_get_estimated_allocated_size(size_t size);
/* Returns true if p was returned by the Msan allocator and
is not yet freed. */
int __msan_get_ownership(const volatile void *p);
/* Returns the number of bytes reserved for the pointer p.
Requires (get_ownership(p) == true) or (p == 0). */
size_t __msan_get_allocated_size(const volatile void *p);
/* Number of bytes, allocated and not yet freed by the application. */
size_t __msan_get_current_allocated_bytes();
/* Number of bytes, mmaped by msan allocator to fulfill allocation requests.
Generally, for request of X bytes, allocator can reserve and add to free
lists a large number of chunks of size X to use them for future requests.
All these chunks count toward the heap size. Currently, allocator never
releases memory to OS (instead, it just puts freed chunks to free
lists). */
size_t __msan_get_heap_size();
/* Number of bytes, mmaped by msan allocator, which can be used to fulfill
allocation requests. When a user program frees memory chunk, it can first
fall into quarantine and will count toward __msan_get_free_bytes()
later. */
size_t __msan_get_free_bytes();
/* Number of bytes in unmapped pages, that are released to OS. Currently,
always returns 0. */
size_t __msan_get_unmapped_bytes();
/* Malloc hooks that may be optionally provided by user.
__msan_malloc_hook(ptr, size) is called immediately after
allocation of "size" bytes, which returned "ptr".
__msan_free_hook(ptr) is called immediately before
deallocation of "ptr". */
void __msan_malloc_hook(const volatile void *ptr, size_t size);
void __msan_free_hook(const volatile void *ptr);
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -120,19 +120,23 @@ const interpose_substitution substitution_##func_name[] \
# define DECLARE_WRAPPER(ret_type, func, ...)
#elif defined(_WIN32)
# if defined(_DLL) // DLL CRT
# define WRAP(x) x
# define WRAPPER_NAME(x) #x
# define INTERCEPTOR_ATTRIBUTE
# else // Static CRT
# define WRAP(x) wrap_##x
# define WRAPPER_NAME(x) "wrap_"#x
# define INTERCEPTOR_ATTRIBUTE
# endif
# define WRAP(x) __asan_wrap_##x
# define WRAPPER_NAME(x) "__asan_wrap_"#x
# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__);
# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
#elif defined(__FreeBSD__)
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
// priority than weak ones so weak aliases won't work for indirect calls
// in position-independent (-fPIC / -fPIE) mode.
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__) \
__attribute__((alias("__interceptor_" #func), visibility("default")));
#else
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
......
......@@ -17,20 +17,6 @@
namespace __interception {
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr) {
const char *DLLS[] = {
"msvcr80.dll",
"msvcr90.dll",
"kernel32.dll",
NULL
};
*func_addr = 0;
for (size_t i = 0; *func_addr == 0 && DLLS[i]; ++i) {
*func_addr = (uptr)GetProcAddress(GetModuleHandleA(DLLS[i]), func_name);
}
return (*func_addr != 0);
}
// FIXME: internal_str* and internal_mem* functions should be moved from the
// ASan sources into interception/.
......@@ -108,9 +94,11 @@ static size_t RoundUpToInstrBoundary(size_t size, char *code) {
case 0x458B: // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
case 0x5D8B: // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
case 0xEC83: // 83 EC XX = sub esp, XX
case 0x75FF: // FF 75 XX = push dword ptr [ebp+XXh]
cursor += 3;
continue;
case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
case 0x25FF: // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
cursor += 6;
continue;
case 0x3D83: // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
......@@ -119,6 +107,7 @@ static size_t RoundUpToInstrBoundary(size_t size, char *code) {
}
switch (0x00FFFFFF & *(unsigned int*)(code + cursor)) {
case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
case 0x24448B: // 8B 44 24 XX = mov eax, dword ptr [esp+XXh]
case 0x244C8B: // 8B 4C 24 XX = mov ecx, dword ptr [esp+XXh]
case 0x24548B: // 8B 54 24 XX = mov edx, dword ptr [esp+XXh]
case 0x24748B: // 8B 74 24 XX = mov esi, dword ptr [esp+XXh]
......@@ -131,8 +120,9 @@ static size_t RoundUpToInstrBoundary(size_t size, char *code) {
// FIXME: Unknown instruction failures might happen when we add a new
// interceptor or a new compiler version. In either case, they should result
// in visible and readable error messages. However, merely calling abort()
// or __debugbreak() leads to an infinite recursion in CheckFailed.
// leads to an infinite recursion in CheckFailed.
// Do we have a good way to abort with an error message here?
__debugbreak();
return 0;
}
......@@ -189,6 +179,33 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
return true;
}
static const void **InterestingDLLsAvailable() {
const char *InterestingDLLs[] = { "kernel32.dll", "msvcr120.dll", NULL };
static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
if (!result[0]) {
for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
result[j++] = (void *)h;
}
}
return (const void **)&result[0];
}
static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
*func_addr = 0;
const void **DLLs = InterestingDLLsAvailable();
for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
*func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
return (*func_addr != 0);
}
bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
uptr orig_func;
if (!GetFunctionAddressInDLLs(name, &orig_func))
return false;
return OverrideFunction(orig_func, new_func, orig_old_func);
}
} // namespace __interception
#endif // _WIN32
......@@ -20,27 +20,29 @@
#define INTERCEPTION_WIN_H
namespace __interception {
// returns true if a function with the given name was found.
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr);
// All the functions in the OverrideFunction() family return true on success,
// false on failure (including "couldn't find the function").
// returns true if the old function existed, false on failure.
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
// Overrides a function by its address.
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
// Overrides a function in a system DLL or DLL CRT by its exported name.
bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
} // namespace __interception
#if defined(_DLL)
# define INTERCEPT_FUNCTION_WIN(func) \
::__interception::GetRealFunctionAddress( \
#func, (::__interception::uptr*)&REAL(func))
#if defined(INTERCEPTION_DYNAMIC_CRT)
#define INTERCEPT_FUNCTION_WIN(func) \
::__interception::OverrideFunction(#func, \
(::__interception::uptr)WRAP(func), \
(::__interception::uptr *)&REAL(func))
#else
# define INTERCEPT_FUNCTION_WIN(func) \
::__interception::OverrideFunction( \
(::__interception::uptr)func, \
(::__interception::uptr)WRAP(func), \
(::__interception::uptr*)&REAL(func))
#define INTERCEPT_FUNCTION_WIN(func) \
::__interception::OverrideFunction((::__interception::uptr)func, \
(::__interception::uptr)WRAP(func), \
(::__interception::uptr *)&REAL(func))
#endif
#define INTERCEPT_FUNCTION_VER_WIN(func, symver) \
INTERCEPT_FUNCTION_WIN(func)
#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
#endif // INTERCEPTION_WIN_H
#endif // _WIN32
......@@ -23,16 +23,6 @@ bool lsan_init_is_running;
namespace __lsan {
static void InitializeCommonFlags() {
CommonFlags *cf = common_flags();
SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
cf->malloc_context_size = 30;
cf->detect_leaks = true;
ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS"));
}
///// Interface to the common LSan module. /////
bool WordIsPoisoned(uptr addr) {
return false;
......@@ -48,7 +38,7 @@ extern "C" void __lsan_init() {
return;
lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
InitializeCommonFlags();
InitCommonLsan(true);
InitializeAllocator();
InitTlsSize();
InitializeInterceptors();
......@@ -58,11 +48,14 @@ extern "C" void __lsan_init() {
ThreadStart(tid, GetTid());
SetCurrentThread(tid);
Symbolizer::Init(common_flags()->external_symbolizer_path);
InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
Atexit(DoLeakCheck);
lsan_inited = true;
lsan_init_is_running = false;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_print_stack_trace() {
GET_STACK_TRACE_FATAL;
stack.Print();
}
......@@ -13,6 +13,26 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#define GET_STACK_TRACE(max_size, fast) \
StackTrace stack; \
{ \
uptr stack_top = 0, stack_bottom = 0; \
ThreadContext *t; \
if (fast && (t = CurrentThreadContext())) { \
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
/* context */ 0, stack_top, stack_bottom, fast); \
}
#define GET_STACK_TRACE_FATAL \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_MALLOC \
GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
common_flags()->fast_unwind_on_malloc)
namespace __lsan {
void InitializeInterceptors();
......
......@@ -13,6 +13,7 @@
#include "lsan_allocator.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
......@@ -51,7 +52,7 @@ void AllocatorThreadFinish() {
allocator.SwallowCache(&cache);
}
static ChunkMetadata *Metadata(void *p) {
static ChunkMetadata *Metadata(const void *p) {
return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
}
......@@ -85,10 +86,12 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
if (cleared && allocator.FromPrimary(p))
memset(p, 0, size);
RegisterAllocation(stack, p, size);
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
return p;
}
void Deallocate(void *p) {
if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
RegisterDeallocation(p);
allocator.Deallocate(&cache, p);
}
......@@ -111,7 +114,7 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end) {
*end = *begin + sizeof(cache);
}
uptr GetMallocUsableSize(void *p) {
uptr GetMallocUsableSize(const void *p) {
ChunkMetadata *m = Metadata(p);
if (!m) return 0;
return m->requested_size;
......@@ -198,3 +201,38 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
}
}
} // namespace __lsan
using namespace __lsan;
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_current_allocated_bytes() {
uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
return stats[AllocatorStatAllocated];
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_heap_size() {
uptr stats[AllocatorStatCount];
allocator.GetStats(stats);
return stats[AllocatorStatMapped];
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_free_bytes() { return 0; }
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_unmapped_bytes() { return 0; }
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; }
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_allocated_size(const void *p) {
return GetMallocUsableSize(p);
}
} // extern "C"
......@@ -23,7 +23,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
void Deallocate(void *p);
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
uptr alignment);
uptr GetMallocUsableSize(void *p);
uptr GetMallocUsableSize(const void *p);
template<typename Callable>
void ForEachChunk(const Callable &callback);
......
......@@ -34,15 +34,13 @@ bool DisabledInThisThread() { return disable_counter > 0; }
Flags lsan_flags;
static void InitializeFlags() {
static void InitializeFlags(bool standalone) {
Flags *f = flags();
// Default values.
f->report_objects = false;
f->resolution = 0;
f->max_leaks = 0;
f->exitcode = 23;
f->print_suppressions = true;
f->suppressions="";
f->use_registers = true;
f->use_globals = true;
f->use_stacks = true;
......@@ -70,9 +68,18 @@ static void InitializeFlags() {
ParseFlag(options, &f->log_pointers, "log_pointers", "");
ParseFlag(options, &f->log_threads, "log_threads", "");
ParseFlag(options, &f->exitcode, "exitcode", "");
ParseFlag(options, &f->print_suppressions, "print_suppressions", "");
ParseFlag(options, &f->suppressions, "suppressions", "");
}
// Set defaults for common flags (only in standalone mode) and parse
// them from LSAN_OPTIONS.
CommonFlags *cf = common_flags();
if (standalone) {
SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
cf->malloc_context_size = 30;
cf->detect_leaks = true;
}
ParseCommonFlagsFromString(cf, options);
}
#define LOG_POINTERS(...) \
......@@ -85,24 +92,14 @@ static void InitializeFlags() {
if (flags()->log_threads) Report(__VA_ARGS__); \
} while (0);
SuppressionContext *suppression_ctx;
static bool suppressions_inited = false;
void InitializeSuppressions() {
CHECK(!suppression_ctx);
ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
suppression_ctx = new(placeholder) SuppressionContext;
char *suppressions_from_file;
uptr buffer_size;
if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file,
&buffer_size, 1 << 26 /* max_len */))
suppression_ctx->Parse(suppressions_from_file);
if (flags()->suppressions[0] && !buffer_size) {
Printf("LeakSanitizer: failed to read suppressions file '%s'\n",
flags()->suppressions);
Die();
}
CHECK(!suppressions_inited);
SuppressionContext::InitIfNecessary();
if (&__lsan_default_suppressions)
suppression_ctx->Parse(__lsan_default_suppressions());
SuppressionContext::Get()->Parse(__lsan_default_suppressions());
suppressions_inited = true;
}
struct RootRegion {
......@@ -118,8 +115,8 @@ void InitializeRootRegions() {
root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
}
void InitCommonLsan() {
InitializeFlags();
void InitCommonLsan(bool standalone) {
InitializeFlags(standalone);
InitializeRootRegions();
if (common_flags()->detect_leaks) {
// Initialization which can fail or print warnings should only be done if
......@@ -129,9 +126,9 @@ void InitCommonLsan() {
}
}
class Decorator: private __sanitizer::AnsiColorDecorator {
class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
Decorator() : SanitizerCommonDecorator() { }
const char *Error() { return Red(); }
const char *Leak() { return Blue(); }
const char *End() { return Default(); }
......@@ -387,7 +384,7 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
static void PrintMatchedSuppressions() {
InternalMmapVector<Suppression *> matched(1);
suppression_ctx->GetMatched(&matched);
SuppressionContext::Get()->GetMatched(&matched);
if (!matched.size())
return;
const char *line = "-----------------------------------------------------";
......@@ -448,7 +445,7 @@ void DoLeakCheck() {
Printf("%s", d.End());
param.leak_report.ReportTopLeaks(flags()->max_leaks);
}
if (flags()->print_suppressions)
if (common_flags()->print_suppressions)
PrintMatchedSuppressions();
if (unsuppressed_count > 0) {
param.leak_report.PrintSummary();
......@@ -463,20 +460,22 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
// Suppress by module name.
const char *module_name;
uptr module_offset;
if (Symbolizer::Get()->GetModuleNameAndOffsetForPC(addr, &module_name,
&module_offset) &&
suppression_ctx->Match(module_name, SuppressionLeak, &s))
if (Symbolizer::GetOrInit()
->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) &&
SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s))
return s;
// Suppress by file or function name.
static const uptr kMaxAddrFrames = 16;
InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
uptr addr_frames_num = Symbolizer::Get()->SymbolizePC(
uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
addr, addr_frames.data(), kMaxAddrFrames);
for (uptr i = 0; i < addr_frames_num; i++) {
if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s))
if (SuppressionContext::Get()->Match(addr_frames[i].function,
SuppressionLeak, &s) ||
SuppressionContext::Get()->Match(addr_frames[i].file, SuppressionLeak,
&s))
return s;
}
return 0;
......
......@@ -49,10 +49,6 @@ struct Flags {
int max_leaks;
// If nonzero kill the process with this exit code upon finding leaks.
int exitcode;
// Print matched suppressions after leak checking.
bool print_suppressions;
// Suppressions file name.
const char* suppressions;
// Flags controlling the root set of reachable memory.
// Global variables (.data and .bss).
......@@ -133,7 +129,7 @@ enum IgnoreObjectResult {
};
// Functions called from the parent tool.
void InitCommonLsan();
void InitCommonLsan(bool standalone);
void DoLeakCheck();
bool DisabledInThisThread();
......
......@@ -32,21 +32,6 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v));
int pthread_setspecific(unsigned key, const void *v);
}
#define GET_STACK_TRACE \
StackTrace stack; \
{ \
uptr stack_top = 0, stack_bottom = 0; \
ThreadContext *t; \
bool fast = common_flags()->fast_unwind_on_malloc; \
if (fast && (t = CurrentThreadContext())) { \
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \
StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), 0, \
stack_top, stack_bottom, fast); \
}
#define ENSURE_LSAN_INITED do { \
CHECK(!lsan_init_is_running); \
if (!lsan_inited) \
......@@ -63,7 +48,7 @@ namespace std {
INTERCEPTOR(void*, malloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
return Allocate(stack, size, 1, kAlwaysClearMemory);
}
......@@ -86,26 +71,32 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
}
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
size *= nmemb;
return Allocate(stack, size, 1, true);
}
INTERCEPTOR(void*, realloc, void *q, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
return Reallocate(stack, q, size, 1);
}
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
return Allocate(stack, size, alignment, kAlwaysClearMemory);
}
INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
return Allocate(stack, size, alignment, kAlwaysClearMemory);
}
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
*memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
// FIXME: Return ENOMEM if user requested more than max alloc size.
return 0;
......@@ -113,7 +104,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
INTERCEPTOR(void*, valloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
if (size == 0)
size = GetPageSizeCached();
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
......@@ -140,7 +131,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {
INTERCEPTOR(void*, pvalloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE;
GET_STACK_TRACE_MALLOC;
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
if (size == 0) {
......@@ -154,7 +145,7 @@ INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
#define OPERATOR_NEW_BODY \
ENSURE_LSAN_INITED; \
GET_STACK_TRACE; \
GET_STACK_TRACE_MALLOC; \
return Allocate(stack, size, 1, kAlwaysClearMemory);
INTERCEPTOR_ATTRIBUTE
......
......@@ -12,11 +12,7 @@
#include "lsan.h"
#ifndef LSAN_USE_PREINIT_ARRAY
#define LSAN_USE_PREINIT_ARRAY 1
#endif
#if LSAN_USE_PREINIT_ARRAY && !defined(PIC)
#if SANITIZER_CAN_USE_PREINIT_ARRAY
// We force __lsan_init to be called before anyone else by placing it into
// .preinit_array section.
__attribute__((section(".preinit_array"), used))
......
......@@ -21,7 +21,8 @@ sanitizer_common_files = \
sanitizer_allocator.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
sanitizer_coverage.cc \
sanitizer_coverage_libcdep.cc \
sanitizer_coverage_mapping_libcdep.cc \
sanitizer_deadlock_detector1.cc \
sanitizer_deadlock_detector2.cc \
sanitizer_flags.cc \
......@@ -30,11 +31,14 @@ sanitizer_common_files = \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
sanitizer_mac.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
sanitizer_posix.cc \
sanitizer_posix_libcdep.cc \
sanitizer_printf.cc \
sanitizer_procmaps_common.cc \
sanitizer_procmaps_freebsd.cc \
sanitizer_procmaps_linux.cc \
sanitizer_procmaps_mac.cc \
sanitizer_stackdepot.cc \
......@@ -49,8 +53,10 @@ sanitizer_common_files = \
sanitizer_symbolizer_win.cc \
sanitizer_thread_registry.cc \
sanitizer_tls_get_addr.cc \
sanitizer_unwind_posix_libcdep.cc \
sanitizer_win.cc
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
# Work around what appears to be a GNU make bug handling MAKEFLAGS
......
......@@ -64,14 +64,17 @@ CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libsanitizer_common_la_LIBADD =
am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_common_libcdep.lo sanitizer_coverage.lo \
sanitizer_common_libcdep.lo sanitizer_coverage_libcdep.lo \
sanitizer_coverage_mapping_libcdep.lo \
sanitizer_deadlock_detector1.lo \
sanitizer_deadlock_detector2.lo sanitizer_flags.lo \
sanitizer_libc.lo sanitizer_libignore.lo sanitizer_linux.lo \
sanitizer_linux_libcdep.lo sanitizer_mac.lo \
sanitizer_persistent_allocator.lo \
sanitizer_platform_limits_linux.lo \
sanitizer_platform_limits_posix.lo sanitizer_posix.lo \
sanitizer_posix_libcdep.lo sanitizer_printf.lo \
sanitizer_procmaps_common.lo sanitizer_procmaps_freebsd.lo \
sanitizer_procmaps_linux.lo sanitizer_procmaps_mac.lo \
sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
sanitizer_stacktrace_libcdep.lo \
......@@ -81,7 +84,8 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_symbolizer_libcdep.lo \
sanitizer_symbolizer_posix_libcdep.lo \
sanitizer_symbolizer_win.lo sanitizer_thread_registry.lo \
sanitizer_tls_get_addr.lo sanitizer_win.lo
sanitizer_tls_get_addr.lo sanitizer_unwind_posix_libcdep.lo \
sanitizer_win.lo
am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
......@@ -256,7 +260,8 @@ sanitizer_common_files = \
sanitizer_allocator.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
sanitizer_coverage.cc \
sanitizer_coverage_libcdep.cc \
sanitizer_coverage_mapping_libcdep.cc \
sanitizer_deadlock_detector1.cc \
sanitizer_deadlock_detector2.cc \
sanitizer_flags.cc \
......@@ -265,11 +270,14 @@ sanitizer_common_files = \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
sanitizer_mac.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
sanitizer_posix.cc \
sanitizer_posix_libcdep.cc \
sanitizer_printf.cc \
sanitizer_procmaps_common.cc \
sanitizer_procmaps_freebsd.cc \
sanitizer_procmaps_linux.cc \
sanitizer_procmaps_mac.cc \
sanitizer_stackdepot.cc \
......@@ -284,6 +292,7 @@ sanitizer_common_files = \
sanitizer_symbolizer_win.cc \
sanitizer_thread_registry.cc \
sanitizer_tls_get_addr.cc \
sanitizer_unwind_posix_libcdep.cc \
sanitizer_win.cc
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
......@@ -382,7 +391,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_mapping_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector1.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector2.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
......@@ -391,11 +401,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_persistent_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_freebsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
......@@ -410,6 +423,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_tls_get_addr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_unwind_posix_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@
.cc.o:
......
......@@ -271,9 +271,9 @@ class AllocatorGlobalStats : public AllocatorStats {
if (stats == this)
break;
}
// All stats must be positive.
// All stats must be non-negative.
for (int i = 0; i < AllocatorStatCount; i++)
s[i] = ((sptr)s[i]) > 0 ? s[i] : 1;
s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
}
private:
......
//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Re-declaration of functions from public sanitizer allocator interface.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
#define SANITIZER_ALLOCATOR_INTERFACE_H
#include "sanitizer_internal_defs.h"
using __sanitizer::uptr;
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_estimated_allocated_size(uptr size);
SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
SANITIZER_INTERFACE_ATTRIBUTE uptr
__sanitizer_get_allocated_size(const void *p);
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
} // extern "C"
#endif // SANITIZER_ALLOCATOR_INTERFACE_H
......@@ -23,38 +23,25 @@ typedef CompactSizeClassMap InternalSizeClassMap;
static const uptr kInternalAllocatorSpace = 0;
static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
#if SANITIZER_WORDSIZE == 32
static const uptr kInternalAllocatorRegionSizeLog = 20;
#if SANITIZER_WORDSIZE == 32
static const uptr kInternalAllocatorNumRegions =
kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
#else
static const uptr kInternalAllocatorRegionSizeLog = 24;
static const uptr kInternalAllocatorNumRegions =
kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
#endif
typedef SizeClassAllocator32<
kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
InternalAllocatorCache;
// We don't want our internal allocator to do any map/unmap operations from
// LargeMmapAllocator.
struct CrashOnMapUnmap {
void OnMap(uptr p, uptr size) const {
RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!\n");
}
void OnUnmap(uptr p, uptr size) const {
RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!\n");
}
};
typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
LargeMmapAllocator<CrashOnMapUnmap> >
InternalAllocator;
LargeMmapAllocator<> > InternalAllocator;
void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
void InternalFree(void *p, InternalAllocatorCache *cache = 0);
......
......@@ -31,33 +31,20 @@ long long _InterlockedCompareExchange64( // NOLINT
long long volatile *Destination, // NOLINT
long long Exchange, long long Comparand); // NOLINT
#pragma intrinsic(_InterlockedCompareExchange64)
#ifdef _WIN64
extern "C" long long _InterlockedExchangeAdd64( // NOLINT
long long volatile * Addend, long long Value); // NOLINT
#pragma intrinsic(_InterlockedExchangeAdd64)
extern "C" void *_InterlockedCompareExchangePointer(
void *volatile *Destination,
void *Exchange, void *Comparand);
#pragma intrinsic(_InterlockedCompareExchangePointer)
#else
// There's no _InterlockedCompareExchangePointer intrinsic on x86,
// so call _InterlockedCompareExchange instead.
extern "C"
long __cdecl _InterlockedCompareExchange( // NOLINT
long volatile *Destination, // NOLINT
long Exchange, long Comparand); // NOLINT
#pragma intrinsic(_InterlockedCompareExchange)
inline static void *_InterlockedCompareExchangePointer(
void *volatile *Destination,
void *Exchange, void *Comparand) {
return reinterpret_cast<void*>(
_InterlockedCompareExchange(
reinterpret_cast<long volatile*>(Destination), // NOLINT
reinterpret_cast<long>(Exchange), // NOLINT
reinterpret_cast<long>(Comparand))); // NOLINT
}
#ifdef _WIN64
extern "C" long long _InterlockedExchangeAdd64( // NOLINT
long long volatile * Addend, long long Value); // NOLINT
#pragma intrinsic(_InterlockedExchangeAdd64)
#endif
namespace __sanitizer {
......
......@@ -12,8 +12,6 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
......@@ -195,31 +193,17 @@ void ReportErrorSummary(const char *error_type, const char *file,
ReportErrorSummary(buff.data());
}
void ReportErrorSummary(const char *error_type, StackTrace *stack) {
if (!common_flags()->print_summary)
return;
AddressInfo ai;
#if !SANITIZER_GO
if (stack->size > 0 && Symbolizer::Get()->CanReturnFileLineInfo()) {
// Currently, we include the first stack frame into the report summary.
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
Symbolizer::Get()->SymbolizePC(pc, &ai, 1);
}
#endif
ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
}
LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
full_name_ = internal_strdup(module_name);
base_address_ = base_address;
n_ranges_ = 0;
}
void LoadedModule::addAddressRange(uptr beg, uptr end) {
void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
ranges_[n_ranges_].beg = beg;
ranges_[n_ranges_].end = end;
exec_[n_ranges_] = executable;
n_ranges_++;
}
......@@ -261,11 +245,6 @@ void DecreaseTotalMmap(uptr size) {
atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
}
static void (*sandboxing_callback)();
void SetSandboxingCallback(void (*f)()) {
sandboxing_callback = f;
}
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
......@@ -298,13 +277,6 @@ void __sanitizer_set_report_path(const char *path) {
}
}
void NOINLINE
__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
PrepareForSandboxing(args);
if (sandboxing_callback)
sandboxing_callback();
}
void __sanitizer_report_error_summary(const char *error_summary) {
Printf("%s\n", error_summary);
}
......
......@@ -163,6 +163,9 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
// (or NULL if the mapping failes). Stores the size of mmaped region
// in '*buff_size'.
void *MapFileToMemory(const char *file_name, uptr *buff_size);
void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
bool IsAccessibleMemoryRange(uptr beg, uptr size);
// Error report formatting.
const char *StripPathPrefix(const char *filepath,
......@@ -173,7 +176,7 @@ void PrintModuleAndOffset(InternalScopedString *buffer,
const char *module, uptr offset);
// OS
void DisableCoreDumper();
void DisableCoreDumperIfNecessary();
void DumpProcessMap();
bool FileExists(const char *filename);
const char *GetEnv(const char *name);
......@@ -184,11 +187,17 @@ u32 GetUid();
void ReExec();
bool StackSizeIsUnlimited();
void SetStackSizeLimitInBytes(uptr limit);
bool AddressSpaceIsUnlimited();
void SetAddressSpaceUnlimited();
void AdjustStackSize(void *attr);
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void SetSandboxingCallback(void (*f)());
void CovUpdateMapping(uptr caller_pc = 0);
void CovBeforeFork();
void CovAfterFork(int child_pid);
void InitTlsSize();
uptr GetTlsSize();
......@@ -239,7 +248,7 @@ const int kMaxSummaryLength = 1024;
// and pass it to __sanitizer_report_error_summary.
void ReportErrorSummary(const char *error_message);
// Same as above, but construct error_message as:
// error_type: file:line function
// error_type file:line function
void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function);
void ReportErrorSummary(const char *error_type, StackTrace *trace);
......@@ -475,12 +484,17 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
class LoadedModule {
public:
LoadedModule(const char *module_name, uptr base_address);
void addAddressRange(uptr beg, uptr end);
void addAddressRange(uptr beg, uptr end, bool executable);
bool containsAddress(uptr address) const;
const char *full_name() const { return full_name_; }
uptr base_address() const { return base_address_; }
uptr n_ranges() const { return n_ranges_; }
uptr address_range_start(int i) const { return ranges_[i].beg; }
uptr address_range_end(int i) const { return ranges_[i].end; }
bool address_range_executable(int i) const { return exec_[i]; }
private:
struct AddressRange {
uptr beg;
......@@ -490,6 +504,7 @@ class LoadedModule {
uptr base_address_;
static const uptr kMaxNumberOfAddressRanges = 6;
AddressRange ranges_[kMaxNumberOfAddressRanges];
bool exec_[kMaxNumberOfAddressRanges];
uptr n_ranges_;
};
......@@ -529,10 +544,13 @@ F IndirectExternCall(F f) {
#endif
#if SANITIZER_ANDROID
// Initialize Android logging. Any writes before this are silently lost.
void AndroidLogInit();
void AndroidLogWrite(const char *buffer);
void GetExtraActivationFlags(char *buf, uptr size);
void SanitizerInitializeUnwinder();
#else
INLINE void AndroidLogInit() {}
INLINE void AndroidLogWrite(const char *buffer_unused) {}
INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
INLINE void SanitizerInitializeUnwinder() {}
......@@ -544,4 +562,9 @@ inline void *operator new(__sanitizer::operator_new_size_type size,
return alloc.Allocate(size);
}
struct StackDepotStats {
uptr n_uniq_ids;
uptr allocated;
};
#endif // SANITIZER_COMMON_H
......@@ -457,6 +457,9 @@ static int printf_get_value_size(PrintfDirective *dir) {
case 8: \
va_arg(*aq, double); \
break; \
case 12: \
va_arg(*aq, long double); \
break; \
case 16: \
va_arg(*aq, long double); \
break; \
......
......@@ -527,7 +527,7 @@ static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
desc->name = "<DECODED_IOCTL>";
desc->size = IOC_SIZE(req);
// Sanity check.
if (desc->size > 1024) return false;
if (desc->size > 0xFFFF) return false;
unsigned dir = IOC_DIR(req);
switch (dir) {
case IOC_NONE:
......@@ -545,10 +545,10 @@ static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
default:
return false;
}
if (desc->type != IOC_NONE && desc->size == 0) return false;
char id = IOC_TYPE(req);
// Size can be 0 iff type is NONE.
if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;
// Sanity check.
if (!(id >= 'a' && id <= 'z') && !(id >= 'A' && id <= 'Z')) return false;
if (IOC_TYPE(req) == 0) return false;
return true;
}
......
......@@ -11,6 +11,8 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
......@@ -39,4 +41,32 @@ bool ColorizeReports() {
return internal_strcmp(flag, "always") == 0 ||
(internal_strcmp(flag, "auto") == 0 && PrintsToTtyCached());
}
static void (*sandboxing_callback)();
void SetSandboxingCallback(void (*f)()) {
sandboxing_callback = f;
}
void ReportErrorSummary(const char *error_type, StackTrace *stack) {
if (!common_flags()->print_summary)
return;
AddressInfo ai;
#if !SANITIZER_GO
if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) {
// Currently, we include the first stack frame into the report summary.
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
Symbolizer::GetOrInit()->SymbolizePC(pc, &ai, 1);
}
#endif
ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
}
} // namespace __sanitizer
void NOINLINE
__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
PrepareForSandboxing(args);
if (sandboxing_callback)
sandboxing_callback();
}
......@@ -829,6 +829,7 @@ POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) {
}
}
#if !SANITIZER_ANDROID
PRE_SYSCALL(statfs)(const void *path, void *buf) {
if (path)
PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
......@@ -866,6 +867,7 @@ POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) {
if (buf) POST_WRITE(buf, struct_statfs64_sz);
}
}
#endif // !SANITIZER_ANDROID
PRE_SYSCALL(lstat)(const void *filename, void *statbuf) {
if (filename)
......@@ -1322,13 +1324,13 @@ PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
} else if (op == iocb_cmd_pread && buf && len) {
POST_WRITE(buf, len);
} else if (op == iocb_cmd_pwritev) {
__sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
__sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
for (uptr v = 0; v < len; v++)
PRE_READ(iovec[i].iov_base, iovec[i].iov_len);
PRE_READ(iovec[v].iov_base, iovec[v].iov_len);
} else if (op == iocb_cmd_preadv) {
__sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
__sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
for (uptr v = 0; v < len; v++)
POST_WRITE(iovec[i].iov_base, iovec[i].iov_len);
POST_WRITE(iovec[v].iov_base, iovec[v].iov_len);
}
// See comment in io_getevents.
COMMON_SYSCALL_RELEASE(data);
......@@ -2293,7 +2295,7 @@ PRE_SYSCALL(ni_syscall)() {}
POST_SYSCALL(ni_syscall)(long res) {}
PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
#if defined(__i386) || defined (__x86_64)
#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
if (data) {
if (request == ptrace_setregs) {
PRE_READ((void *)data, struct_user_regs_struct_sz);
......@@ -2312,7 +2314,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
}
POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
#if defined(__i386) || defined (__x86_64)
#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
if (res >= 0 && data) {
// Note that this is different from the interceptor in
// sanitizer_common_interceptors.inc.
......
//===-- sanitizer_coverage.cc ---------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Sanitizer Coverage.
// This file implements run-time support for a poor man's coverage tool.
//
// Compiler instrumentation:
// For every interesting basic block the compiler injects the following code:
// if (*Guard) {
// __sanitizer_cov();
// *Guard = 1;
// }
// It's fine to call __sanitizer_cov more than once for a given block.
//
// Run-time:
// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
// - __sanitizer_cov_dump: dump the coverage data to disk.
// For every module of the current process that has coverage data
// this will create a file module_name.PID.sancov. The file format is simple:
// it's just a sorted sequence of 4-byte offsets in the module.
//
// Eventually, this coverage implementation should be obsoleted by a more
// powerful general purpose Clang/LLVM coverage instrumentation.
// Consider this implementation as prototype.
//
// FIXME: support (or at least test with) dlclose.
//===----------------------------------------------------------------------===//
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_flags.h"
atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
// 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.
// 128M counters "ought to be enough for anybody" (4M on 32-bit).
// pc_array is allocated with MmapNoReserveOrDie and so it uses only as
// much RAM as it really needs.
static const uptr kPcArraySize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
static uptr *pc_array;
static atomic_uintptr_t pc_array_index;
static bool cov_sandboxed = false;
static int cov_fd = kInvalidFd;
static unsigned int cov_max_block_size = 0;
namespace __sanitizer {
// Simply add the pc into the vector under lock. If the function is called more
// than once for a given PC it will be inserted multiple times, which is fine.
static void CovAdd(uptr pc) {
if (!pc_array) return;
uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
CHECK_LT(idx, kPcArraySize);
pc_array[idx] = pc;
}
void CovInit() {
pc_array = reinterpret_cast<uptr *>(
MmapNoReserveOrDie(sizeof(uptr) * kPcArraySize, "CovInit"));
}
static inline bool CompareLess(const uptr &a, const uptr &b) {
return a < b;
}
// Block layout for packed file format: header, followed by module name (no
// trailing zero), followed by data blob.
struct CovHeader {
int pid;
unsigned int module_name_length;
unsigned int data_length;
};
static void CovWritePacked(int pid, const char *module, const void *blob,
unsigned int blob_size) {
CHECK_GE(cov_fd, 0);
unsigned module_name_length = internal_strlen(module);
CovHeader header = {pid, module_name_length, blob_size};
if (cov_max_block_size == 0) {
// Writing to a file. Just go ahead.
internal_write(cov_fd, &header, sizeof(header));
internal_write(cov_fd, module, module_name_length);
internal_write(cov_fd, blob, blob_size);
} else {
// Writing to a socket. We want to split the data into appropriately sized
// blocks.
InternalScopedBuffer<char> block(cov_max_block_size);
CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
uptr header_size_with_module = sizeof(header) + module_name_length;
CHECK_LT(header_size_with_module, cov_max_block_size);
unsigned int max_payload_size =
cov_max_block_size - header_size_with_module;
char *block_pos = block.data();
internal_memcpy(block_pos, &header, sizeof(header));
block_pos += sizeof(header);
internal_memcpy(block_pos, module, module_name_length);
block_pos += module_name_length;
char *block_data_begin = block_pos;
char *blob_pos = (char *)blob;
while (blob_size > 0) {
unsigned int payload_size = Min(blob_size, max_payload_size);
blob_size -= payload_size;
internal_memcpy(block_data_begin, blob_pos, payload_size);
blob_pos += payload_size;
((CovHeader *)block.data())->data_length = payload_size;
internal_write(cov_fd, block.data(),
header_size_with_module + payload_size);
}
}
}
// Dump the coverage on disk.
static void CovDump() {
if (!common_flags()->coverage) return;
#if !SANITIZER_WINDOWS
if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
return;
uptr size = atomic_load(&pc_array_index, memory_order_relaxed);
InternalSort(&pc_array, size, CompareLess);
InternalMmapVector<u32> offsets(size);
const uptr *vb = pc_array;
const uptr *ve = vb + size;
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
uptr mb, me, off, prot;
InternalScopedBuffer<char> module(4096);
InternalScopedBuffer<char> path(4096 * 2);
for (int i = 0;
proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
i++) {
if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
continue;
while (vb < ve && *vb < mb) vb++;
if (vb >= ve) break;
if (*vb < me) {
offsets.clear();
const uptr *old_vb = vb;
CHECK_LE(off, *vb);
for (; vb < ve && *vb < me; vb++) {
uptr diff = *vb - (i ? mb : 0) + off;
CHECK_LE(diff, 0xffffffffU);
offsets.push_back(static_cast<u32>(diff));
}
char *module_name = StripModuleName(module.data());
if (cov_sandboxed) {
CovWritePacked(internal_getpid(), module_name, offsets.data(),
offsets.size() * sizeof(u32));
VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb);
} else {
// One file per module per process.
internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
module_name, internal_getpid());
uptr fd = OpenFile(path.data(), true);
if (internal_iserror(fd)) {
Report(" CovDump: failed to open %s for writing\n", path.data());
} else {
internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
internal_close(fd);
VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
vb - old_vb);
}
}
InternalFree(module_name);
}
}
if (cov_fd >= 0)
internal_close(cov_fd);
#endif // !SANITIZER_WINDOWS
}
static void OpenPackedFileForWriting() {
CHECK(cov_fd == kInvalidFd);
InternalScopedBuffer<char> path(1024);
internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.packed",
internal_getpid());
uptr fd = OpenFile(path.data(), true);
if (internal_iserror(fd)) {
Report(" Coverage: failed to open %s for writing\n", path.data());
Die();
}
cov_fd = fd;
}
void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
if (!args) return;
if (!common_flags()->coverage) return;
cov_sandboxed = args->coverage_sandboxed;
if (!cov_sandboxed) return;
cov_fd = args->coverage_fd;
cov_max_block_size = args->coverage_max_block_size;
if (cov_fd < 0)
// Pre-open the file now. The sandbox won't allow us to do it later.
OpenPackedFileForWriting();
}
} // namespace __sanitizer
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() {
CovAdd(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()));
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { CovInit(); }
} // extern "C"
//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Mmap-based implementation of sanitizer coverage.
//
// This is part of the implementation of code coverage that does not require
// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
//
// $pid.sancov.map describes process memory layout in the following text-based
// format:
// <pointer size in bits> // 1 line, 32 or 64
// <mapping start> <mapping end> <base address> <dso name> // repeated
// ...
// Mapping lines are NOT sorted. This file is updated every time memory layout
// is changed (i.e. in dlopen() and dlclose() interceptors).
//
// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
// sorted. This file is extended by 64Kb at a time and mapped into memory. It
// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
//
// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
// $pid.sancov.raw.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_allocator_internal.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"
namespace __sanitizer {
static const uptr kMaxNumberOfModules = 1 << 14;
static const uptr kMaxTextSize = 64 * 1024;
struct CachedMapping {
public:
bool NeedsUpdate(uptr pc) {
int new_pid = internal_getpid();
if (last_pid == new_pid && pc && pc >= last_range_start &&
pc < last_range_end)
return false;
last_pid = new_pid;
return true;
}
void SetModuleRange(uptr start, uptr end) {
last_range_start = start;
last_range_end = end;
}
private:
uptr last_range_start, last_range_end;
int last_pid;
};
static CachedMapping cached_mapping;
static StaticSpinMutex mapping_mu;
void CovUpdateMapping(uptr caller_pc) {
if (!common_flags()->coverage || !common_flags()->coverage_direct) return;
SpinMutexLock l(&mapping_mu);
if (!cached_mapping.NeedsUpdate(caller_pc))
return;
InternalScopedString text(kMaxTextSize);
InternalScopedBuffer<char> modules_data(kMaxNumberOfModules *
sizeof(LoadedModule));
LoadedModule *modules = (LoadedModule *)modules_data.data();
CHECK(modules);
int n_modules = GetListOfModules(modules, kMaxNumberOfModules,
/* filter */ 0);
text.append("%d\n", sizeof(uptr) * 8);
for (int i = 0; i < n_modules; ++i) {
char *module_name = StripModuleName(modules[i].full_name());
for (unsigned j = 0; j < modules[i].n_ranges(); ++j) {
if (modules[i].address_range_executable(j)) {
uptr start = modules[i].address_range_start(j);
uptr end = modules[i].address_range_end(j);
uptr base = modules[i].base_address();
text.append("%zx %zx %zx %s\n", start, end, base, module_name);
if (caller_pc && caller_pc >= start && caller_pc < end)
cached_mapping.SetModuleRange(start, end);
}
}
InternalFree(module_name);
}
int err;
InternalScopedString tmp_path(64 +
internal_strlen(common_flags()->coverage_dir));
uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
"%s/%zd.sancov.map.tmp", common_flags()->coverage_dir,
internal_getpid());
CHECK_LE(res, tmp_path.size());
uptr map_fd = OpenFile(tmp_path.data(), true);
if (internal_iserror(map_fd)) {
Report(" Coverage: failed to open %s for writing\n", tmp_path.data());
Die();
}
res = internal_write(map_fd, text.data(), text.length());
if (internal_iserror(res, &err)) {
Printf("sancov.map write failed: %d\n", err);
Die();
}
internal_close(map_fd);
InternalScopedString path(64 + internal_strlen(common_flags()->coverage_dir));
res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
common_flags()->coverage_dir, internal_getpid());
CHECK_LE(res, path.size());
res = internal_rename(tmp_path.data(), path.data());
if (internal_iserror(res, &err)) {
Printf("sancov.map rename failed: %d\n", err);
Die();
}
}
} // namespace __sanitizer
......@@ -185,8 +185,7 @@ u32 DD::allocateId(DDCallback *cb) {
id = id_gen++;
}
CHECK_LE(id, kMaxMutex);
VPrintf(3, "#%llu: DD::allocateId assign id %d\n",
cb->lt->ctx, id);
VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id);
return id;
}
......
......@@ -27,6 +27,11 @@ struct FlagDescription {
IntrusiveList<FlagDescription> flag_descriptions;
// If set, the tool will install its own SEGV signal handler by default.
#ifndef SANITIZER_NEEDS_SEGV
# define SANITIZER_NEEDS_SEGV 1
#endif
void SetCommonFlagsDefaults(CommonFlags *f) {
f->symbolize = true;
f->external_symbolizer_path = 0;
......@@ -53,7 +58,12 @@ void SetCommonFlagsDefaults(CommonFlags *f) {
f->legacy_pthread_cond = false;
f->intercept_tls_get_addr = false;
f->coverage = false;
f->coverage_direct = SANITIZER_ANDROID;
f->coverage_dir = ".";
f->full_address_space = false;
f->suppressions = "";
f->print_suppressions = true;
f->disable_coredump = (SANITIZER_WORDSIZE == 64);
}
void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
......@@ -125,9 +135,23 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
ParseFlag(str, &f->coverage, "coverage",
"If set, coverage information will be dumped at program shutdown (if the "
"coverage instrumentation was enabled at compile time).");
ParseFlag(str, &f->coverage_direct, "coverage_direct",
"If set, coverage information will be dumped directly to a memory "
"mapped file. This way data is not lost even if the process is "
"suddenly killed.");
ParseFlag(str, &f->coverage_dir, "coverage_dir",
"Target directory for coverage dumps. Defaults to the current "
"directory.");
ParseFlag(str, &f->full_address_space, "full_address_space",
"Sanitize complete address space; "
"by default kernel area on 32-bit platforms will not be sanitized");
ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name.");
ParseFlag(str, &f->print_suppressions, "print_suppressions",
"Print matched suppressions at exit.");
ParseFlag(str, &f->disable_coredump, "disable_coredump",
"Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
"dumping a 16T+ core file. Ignored on OSes that don't dump core by"
"default and for sanitizers that don't reserve lots of virtual memory.");
// Do a sanity check for certain flags.
if (f->malloc_context_size < 1)
......@@ -143,14 +167,17 @@ static bool GetFlagValue(const char *env, const char *name,
pos = internal_strstr(env, name);
if (pos == 0)
return false;
if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) {
const char *name_end = pos + internal_strlen(name);
if ((pos != env &&
((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) ||
*name_end != '=') {
// Seems to be middle of another flag name or value.
env = pos + 1;
continue;
}
pos = name_end;
break;
}
pos += internal_strlen(name);
const char *end;
if (pos[0] != '=') {
end = pos;
......
......@@ -52,7 +52,12 @@ struct CommonFlags {
bool help;
uptr mmap_limit_mb;
bool coverage;
bool coverage_direct;
const char *coverage_dir;
bool full_address_space;
const char *suppressions;
bool print_suppressions;
bool disable_coredump;
};
inline CommonFlags *common_flags() {
......
//===-- sanitizer_freebsd.h -------------------------------------*- C++ -*-===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of Sanitizer runtime. It contains FreeBSD-specific
// definitions.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_FREEBSD_H
#define SANITIZER_FREEBSD_H
#include "sanitizer_internal_defs.h"
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
// 32-bit mode.
#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
# include <osreldate.h>
# if __FreeBSD_version <= 902001 // v9.2
# include <link.h>
# include <sys/param.h>
# include <ucontext.h>
namespace __sanitizer {
typedef unsigned long long __xuint64_t;
typedef __int32_t __xregister_t;
typedef struct __xmcontext {
__xregister_t mc_onstack;
__xregister_t mc_gs;
__xregister_t mc_fs;
__xregister_t mc_es;
__xregister_t mc_ds;
__xregister_t mc_edi;
__xregister_t mc_esi;
__xregister_t mc_ebp;
__xregister_t mc_isp;
__xregister_t mc_ebx;
__xregister_t mc_edx;
__xregister_t mc_ecx;
__xregister_t mc_eax;
__xregister_t mc_trapno;
__xregister_t mc_err;
__xregister_t mc_eip;
__xregister_t mc_cs;
__xregister_t mc_eflags;
__xregister_t mc_esp;
__xregister_t mc_ss;
int mc_len;
int mc_fpformat;
int mc_ownedfp;
__xregister_t mc_flags;
int mc_fpstate[128] __aligned(16);
__xregister_t mc_fsbase;
__xregister_t mc_gsbase;
__xregister_t mc_xfpustate;
__xregister_t mc_xfpustate_len;
int mc_spare2[4];
} xmcontext_t;
typedef struct __xucontext {
sigset_t uc_sigmask;
xmcontext_t uc_mcontext;
struct __ucontext *uc_link;
stack_t uc_stack;
int uc_flags;
int __spare__[4];
} xucontext_t;
struct xkinfo_vmentry {
int kve_structsize;
int kve_type;
__xuint64_t kve_start;
__xuint64_t kve_end;
__xuint64_t kve_offset;
__xuint64_t kve_vn_fileid;
__uint32_t kve_vn_fsid;
int kve_flags;
int kve_resident;
int kve_private_resident;
int kve_protection;
int kve_ref_count;
int kve_shadow_count;
int kve_vn_type;
__xuint64_t kve_vn_size;
__uint32_t kve_vn_rdev;
__uint16_t kve_vn_mode;
__uint16_t kve_status;
int _kve_ispare[12];
char kve_path[PATH_MAX];
};
typedef struct {
__uint32_t p_type;
__uint32_t p_offset;
__uint32_t p_vaddr;
__uint32_t p_paddr;
__uint32_t p_filesz;
__uint32_t p_memsz;
__uint32_t p_flags;
__uint32_t p_align;
} XElf32_Phdr;
struct xdl_phdr_info {
Elf_Addr dlpi_addr;
const char *dlpi_name;
const XElf32_Phdr *dlpi_phdr;
Elf_Half dlpi_phnum;
unsigned long long int dlpi_adds;
unsigned long long int dlpi_subs;
size_t dlpi_tls_modid;
void *dlpi_tls_data;
};
typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
#define xdl_iterate_phdr(callback, param) \
(((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
} // namespace __sanitizer
# endif // __FreeBSD_version <= 902001
#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
#endif // SANITIZER_FREEBSD_H
......@@ -32,9 +32,13 @@
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
// If set, the tool will install its own SEGV signal handler.
#ifndef SANITIZER_NEEDS_SEGV
# define SANITIZER_NEEDS_SEGV 1
// We can use .preinit_array section on Linux to call sanitizer initialization
// functions very early in the process startup (unless PIC macro is defined).
// FIXME: do we have anything like this on Mac?
#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
#else
# define SANITIZER_CAN_USE_PREINIT_ARRAY 0
#endif
// GCC does not understand __has_feature
......
......@@ -72,6 +72,7 @@ uptr internal_open(const char *filename, int flags, u32 mode);
uptr internal_read(fd_t fd, void *buf, uptr count);
uptr internal_write(fd_t fd, const void *buf, uptr count);
uptr internal_ftruncate(fd_t fd, uptr size);
// OS
uptr internal_filesize(fd_t fd); // -1 on error.
......@@ -81,6 +82,7 @@ uptr internal_fstat(fd_t fd, void *buf);
uptr internal_dup2(int oldfd, int newfd);
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
uptr internal_unlink(const char *path);
uptr internal_rename(const char *oldpath, const char *newpath);
void NORETURN internal__exit(int exitcode);
uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
......
......@@ -6,7 +6,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_LINUX
#if SANITIZER_FREEBSD || SANITIZER_LINUX
#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
......@@ -101,4 +101,4 @@ void LibIgnore::OnLibraryUnloaded() {
} // namespace __sanitizer
#endif // #if SANITIZER_LINUX
#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
......@@ -44,15 +44,16 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <unwind.h>
#if SANITIZER_FREEBSD
#include <sys/sysctl.h>
#include <machine/atomic.h>
extern "C" {
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
// FreeBSD 9.2 and 10.0.
#include <sys/umtx.h>
}
extern char **environ; // provided by crt1
#endif // SANITIZER_FREEBSD
#if !SANITIZER_ANDROID
......@@ -132,7 +133,7 @@ uptr internal_open(const char *filename, int flags, u32 mode) {
uptr OpenFile(const char *filename, bool write) {
return internal_open(filename,
write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}
uptr internal_read(fd_t fd, void *buf, uptr count) {
......@@ -149,6 +150,12 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return res;
}
uptr internal_ftruncate(fd_t fd, uptr size) {
sptr res;
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
return res;
}
#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
......@@ -244,6 +251,15 @@ uptr internal_unlink(const char *path) {
#endif
}
uptr internal_rename(const char *oldpath, const char *newpath) {
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
(uptr)newpath);
#else
return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
#endif
}
uptr internal_sched_yield() {
return internal_syscall(SYSCALL(sched_yield));
}
......@@ -297,9 +313,20 @@ u64 NanoTime() {
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
// Like getenv, but reads env directly from /proc and does not use libc.
// This function should be called first inside __asan_init.
// Like getenv, but reads env directly from /proc (on Linux) or parses the
// 'environ' array (on FreeBSD) and does not use libc. This function should be
// called first inside __asan_init.
const char *GetEnv(const char *name) {
#if SANITIZER_FREEBSD
if (::environ != 0) {
uptr NameLen = internal_strlen(name);
for (char **Env = ::environ; *Env != 0; Env++) {
if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
return (*Env) + NameLen + 1;
}
}
return 0; // Not found.
#elif SANITIZER_LINUX
static char *environ;
static uptr len;
static bool inited;
......@@ -323,6 +350,9 @@ const char *GetEnv(const char *name) {
p = endp + 1;
}
return 0; // Not found.
#else
#error "Unsupported platform"
#endif
}
extern "C" {
......@@ -388,20 +418,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
}
#endif // SANITIZER_GO
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
// Some kinds of sandboxes may forbid filesystem access, so we won't be able
// to read the file mappings from /proc/self/maps. Luckily, neither the
// process will be able to load additional libraries, so it's fine to use the
// cached mappings.
MemoryMappingLayout::CacheMemoryMappings();
// Same for /proc/self/exe in the symbolizer.
#if !SANITIZER_GO
if (Symbolizer *sym = Symbolizer::GetOrNull())
sym->PrepareForSandboxing();
CovPrepareForSandboxing(args);
#endif
}
enum MutexState {
MtxUnlocked = 0,
MtxLocked = 1,
......@@ -506,7 +522,11 @@ uptr internal_sigaltstack(const struct sigaltstack *ss,
}
int internal_fork() {
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
#else
return internal_syscall(SYSCALL(fork));
#endif
}
#if SANITIZER_LINUX
......@@ -660,24 +680,32 @@ static char proc_self_exe_cache_str[kMaxPathLength];
static uptr proc_self_exe_cache_len = 0;
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
if (proc_self_exe_cache_len > 0) {
// If available, use the cached module name.
uptr module_name_len =
internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str);
CHECK_LT(module_name_len, buf_len);
return module_name_len;
}
#if SANITIZER_FREEBSD
const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
size_t Size = buf_len;
bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0);
int readlink_error = IsErr ? errno : 0;
uptr module_name_len = Size;
#else
uptr module_name_len = internal_readlink(
"/proc/self/exe", buf, buf_len);
int readlink_error;
if (internal_iserror(module_name_len, &readlink_error)) {
if (proc_self_exe_cache_len) {
// If available, use the cached module name.
CHECK_LE(proc_self_exe_cache_len, buf_len);
internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
module_name_len = internal_strlen(proc_self_exe_cache_str);
} else {
// We can't read /proc/self/exe for some reason, assume the name of the
// binary is unknown.
Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
"some stack frames may not be symbolized\n", readlink_error);
module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
}
bool IsErr = internal_iserror(module_name_len, &readlink_error);
#endif
if (IsErr) {
// We can't read /proc/self/exe for some reason, assume the name of the
// binary is unknown.
Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
"some stack frames may not be symbolized\n", readlink_error);
module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
CHECK_LT(module_name_len, buf_len);
buf[module_name_len] = '\0';
}
return module_name_len;
}
......@@ -806,11 +834,19 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
#endif // defined(__x86_64__) && SANITIZER_LINUX
#if SANITIZER_ANDROID
static atomic_uint8_t android_log_initialized;
void AndroidLogInit() {
atomic_store(&android_log_initialized, 1, memory_order_release);
}
// This thing is not, strictly speaking, async signal safe, but it does not seem
// to cause any issues. Alternative is writing to log devices directly, but
// their location and message format might change in the future, so we'd really
// like to avoid that.
void AndroidLogWrite(const char *buffer) {
if (!atomic_load(&android_log_initialized, memory_order_acquire))
return;
char *copy = internal_strdup(buffer);
char *p = copy;
char *q;
......
......@@ -15,23 +15,25 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
#include "sanitizer_freebsd.h"
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_atomic.h"
#include "sanitizer_symbolizer.h"
#if SANITIZER_ANDROID || SANITIZER_FREEBSD
#include <dlfcn.h> // for dlsym()
#endif
#include <dlfcn.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#if SANITIZER_FREEBSD
#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h>
#endif
#include <unwind.h>
#if SANITIZER_FREEBSD
#include <pthread_np.h>
#include <osreldate.h>
#define pthread_getattr_np pthread_attr_get_np
#endif
......@@ -147,127 +149,6 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#endif
}
//------------------------- SlowUnwindStack -----------------------------------
typedef struct {
uptr absolute_pc;
uptr stack_top;
uptr stack_size;
} backtrace_frame_t;
extern "C" {
typedef void *(*acquire_my_map_info_list_func)();
typedef void (*release_my_map_info_list_func)(void *map);
typedef sptr (*unwind_backtrace_signal_arch_func)(
void *siginfo, void *sigcontext, void *map_info_list,
backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
acquire_my_map_info_list_func acquire_my_map_info_list;
release_my_map_info_list_func release_my_map_info_list;
unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
} // extern "C"
#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder() {
void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
if (!p) {
VReport(1,
"Failed to open libcorkscrew.so. You may see broken stack traces "
"in SEGV reports.");
return;
}
acquire_my_map_info_list =
(acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
release_my_map_info_list =
(release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
p, "unwind_backtrace_signal_arch");
if (!acquire_my_map_info_list || !release_my_map_info_list ||
!unwind_backtrace_signal_arch) {
VReport(1,
"Failed to find one of the required symbols in libcorkscrew.so. "
"You may see broken stack traces in SEGV reports.");
acquire_my_map_info_list = NULL;
unwind_backtrace_signal_arch = NULL;
release_my_map_info_list = NULL;
}
}
#endif
#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif
uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
#ifdef __arm__
uptr val;
_Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
15 /* r15 = PC */, _UVRSD_UINT32, &val);
CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
// Clear the Thumb bit.
return val & ~(uptr)1;
#else
return _Unwind_GetIP(ctx);
#endif
}
struct UnwindTraceArg {
StackTrace *stack;
uptr max_depth;
};
_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
UnwindTraceArg *arg = (UnwindTraceArg*)param;
CHECK_LT(arg->stack->size, arg->max_depth);
uptr pc = Unwind_GetIP(ctx);
arg->stack->trace[arg->stack->size++] = pc;
if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
return UNWIND_CONTINUE;
}
void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
CHECK_GE(max_depth, 2);
size = 0;
UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
_Unwind_Backtrace(Unwind_Trace, &arg);
// We need to pop a few frames so that pc is on top.
uptr to_pop = LocatePcInTrace(pc);
// trace[0] belongs to the current function so we always pop it.
if (to_pop == 0)
to_pop = 1;
PopStackFrames(to_pop);
trace[0] = pc;
}
void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
uptr max_depth) {
CHECK_GE(max_depth, 2);
if (!unwind_backtrace_signal_arch) {
SlowUnwindStack(pc, max_depth);
return;
}
void *map = acquire_my_map_info_list();
CHECK(map);
InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
// siginfo argument appears to be unused.
sptr res = unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map,
frames.data(),
/* ignore_depth */ 0, max_depth);
release_my_map_info_list(map);
if (res < 0) return;
CHECK_LE((uptr)res, kStackTraceMax);
size = 0;
// +2 compensate for libcorkscrew unwinder returning addresses of call
// instructions instead of raw return addresses.
for (sptr i = 0; i < res; ++i)
trace[size++] = frames[i].absolute_pc + 2;
}
#if !SANITIZER_FREEBSD
static uptr g_tls_size;
#endif
......@@ -299,11 +180,11 @@ void InitTlsSize() {
static atomic_uintptr_t kThreadDescriptorSize;
uptr ThreadDescriptorSize() {
char buf[64];
uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
if (val)
return val;
#ifdef _CS_GNU_LIBC_VERSION
char buf[64];
uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
char *end;
......@@ -468,6 +349,10 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
#else // SANITIZER_ANDROID
# if !SANITIZER_FREEBSD
typedef ElfW(Phdr) Elf_Phdr;
# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
# define Elf_Phdr XElf32_Phdr
# define dl_phdr_info xdl_phdr_info
# define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
# endif
struct DlIteratePhdrData {
......@@ -504,7 +389,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
if (phdr->p_type == PT_LOAD) {
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
uptr cur_end = cur_beg + phdr->p_memsz;
cur_module->addAddressRange(cur_beg, cur_end);
bool executable = phdr->p_flags & PF_X;
cur_module->addAddressRange(cur_beg, cur_end, executable);
}
}
return 0;
......@@ -527,6 +413,19 @@ void SetIndirectCallWrapper(uptr wrapper) {
indirect_call_wrapper = wrapper;
}
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
// Some kinds of sandboxes may forbid filesystem access, so we won't be able
// to read the file mappings from /proc/self/maps. Luckily, neither the
// process will be able to load additional libraries, so it's fine to use the
// cached mappings.
MemoryMappingLayout::CacheMemoryMappings();
// Same for /proc/self/exe in the symbolizer.
#if !SANITIZER_GO
Symbolizer::GetOrInit()->PrepareForSandboxing();
CovPrepareForSandboxing(args);
#endif
}
} // namespace __sanitizer
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
......@@ -129,6 +129,14 @@ int internal_fork() {
return fork();
}
uptr internal_rename(const char *oldpath, const char *newpath) {
return rename(oldpath, newpath);
}
uptr internal_ftruncate(fd_t fd, uptr size) {
return ftruncate(fd, size);
}
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
struct stat st;
......
//===-- sanitizer_persistent_allocator.cc -----------------------*- C++ -*-===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//
#include "sanitizer_persistent_allocator.h"
namespace __sanitizer {
PersistentAllocator thePersistentAllocator;
} // namespace __sanitizer
//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// A fast memory allocator that does not support free() nor realloc().
// All allocations are forever.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
#define SANITIZER_PERSISTENT_ALLOCATOR_H
#include "sanitizer_internal_defs.h"
#include "sanitizer_mutex.h"
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
namespace __sanitizer {
class PersistentAllocator {
public:
void *alloc(uptr size);
private:
void *tryAlloc(uptr size);
StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator.
atomic_uintptr_t region_pos; // Region allocator for Node's.
atomic_uintptr_t region_end;
};
inline void *PersistentAllocator::tryAlloc(uptr size) {
// Optimisic lock-free allocation, essentially try to bump the region ptr.
for (;;) {
uptr cmp = atomic_load(&region_pos, memory_order_acquire);
uptr end = atomic_load(&region_end, memory_order_acquire);
if (cmp == 0 || cmp + size > end) return 0;
if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
memory_order_acquire))
return (void *)cmp;
}
}
inline void *PersistentAllocator::alloc(uptr size) {
// First, try to allocate optimisitically.
void *s = tryAlloc(size);
if (s) return s;
// If failed, lock, retry and alloc new superblock.
SpinMutexLock l(&mtx);
for (;;) {
s = tryAlloc(size);
if (s) return s;
atomic_store(&region_pos, 0, memory_order_relaxed);
uptr allocsz = 64 * 1024;
if (allocsz < size) allocsz = size;
uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
atomic_store(&region_end, mem + allocsz, memory_order_release);
atomic_store(&region_pos, mem, memory_order_release);
}
}
extern PersistentAllocator thePersistentAllocator;
inline void *PersistentAlloc(uptr sz) {
return thePersistentAllocator.alloc(sz);
}
} // namespace __sanitizer
#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
......@@ -27,6 +27,12 @@
# define SI_LINUX_NOT_ANDROID 0
#endif
#if SANITIZER_FREEBSD
# define SI_FREEBSD 1
#else
# define SI_FREEBSD 0
#endif
#if SANITIZER_LINUX
# define SI_LINUX 1
#else
......@@ -73,11 +79,11 @@
#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
#ifndef SANITIZER_INTERCEPT_PRINTF
# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX
# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
#endif
#define SANITIZER_INTERCEPT_FREXP 1
......@@ -86,10 +92,10 @@
#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETPWENT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETPWENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SETPWENT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
......@@ -102,9 +108,12 @@
#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
......@@ -117,13 +126,13 @@
(defined(__i386) || defined (__x86_64)) // NOLINT
#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
......@@ -140,19 +149,21 @@
#define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SIGSETOPS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SIGSETOPS \
SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_STATFS SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATFS64 \
(SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_ETHER_HOST SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SHMCTL \
(SI_LINUX_NOT_ANDROID && SANITIZER_WORDSIZE == 64)
......@@ -161,6 +172,19 @@
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \
SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
......@@ -168,6 +192,7 @@
#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID
......@@ -176,7 +201,7 @@
// FIXME: getline seems to be available on OSX 10.7
#define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT__EXIT SI_LINUX
#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
......@@ -201,5 +226,10 @@
#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_LINUX_NOT_ANDROID || SI_MAC
#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
......@@ -27,7 +27,7 @@
// are not defined anywhere in userspace headers. Fake them. This seems to work
// fine with newer headers, too.
#include <asm/posix_types.h>
#if defined(__x86_64__)
#if defined(__x86_64__) || defined(__mips__)
#include <sys/stat.h>
#else
#define ino_t __kernel_ino_t
......@@ -48,21 +48,19 @@
#include <linux/aio_abi.h>
#if SANITIZER_ANDROID
#include <asm/statfs.h>
#else
#include <sys/statfs.h>
#endif
#if !SANITIZER_ANDROID
#include <sys/statfs.h>
#include <linux/perf_event.h>
#endif
namespace __sanitizer {
#if !SANITIZER_ANDROID
unsigned struct_statfs64_sz = sizeof(struct statfs64);
#endif
} // namespace __sanitizer
#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)
#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\
&& !defined(__mips__)
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
#endif
......
......@@ -33,7 +33,6 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/utsname.h>
......@@ -43,6 +42,7 @@
#if !SANITIZER_ANDROID
#include <sys/mount.h>
#include <sys/timeb.h>
#endif
#if SANITIZER_LINUX
......@@ -189,13 +189,14 @@ namespace __sanitizer {
unsigned struct_tms_sz = sizeof(struct tms);
unsigned struct_sigevent_sz = sizeof(struct sigevent);
unsigned struct_sched_param_sz = sizeof(struct sched_param);
unsigned struct_statfs_sz = sizeof(struct statfs);
#if SANITIZER_MAC && !SANITIZER_IOS
unsigned struct_statfs64_sz = sizeof(struct statfs64);
#endif // SANITIZER_MAC && !SANITIZER_IOS
#if !SANITIZER_ANDROID
unsigned struct_statfs_sz = sizeof(struct statfs);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
unsigned ucontext_t_sz = sizeof(ucontext_t);
#endif // !SANITIZER_ANDROID
......@@ -287,6 +288,7 @@ namespace __sanitizer {
int ptrace_setfpregs = PTRACE_SETFPREGS;
int ptrace_getfpxregs = PTRACE_GETFPXREGS;
int ptrace_setfpxregs = PTRACE_SETFPXREGS;
int ptrace_geteventmsg = PTRACE_GETEVENTMSG;
#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \
(defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
int ptrace_getsiginfo = PTRACE_GETSIGINFO;
......@@ -396,7 +398,7 @@ namespace __sanitizer {
unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
#endif
unsigned IOCTL_NOT_PRESENT = 0;
const unsigned IOCTL_NOT_PRESENT = 0;
unsigned IOCTL_FIOASYNC = FIOASYNC;
unsigned IOCTL_FIOCLEX = FIOCLEX;
......@@ -1056,6 +1058,10 @@ CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
CHECK_TYPE_SIZE(clock_t);
#if SANITIZER_LINUX
CHECK_TYPE_SIZE(clockid_t);
#endif
#if !SANITIZER_ANDROID
CHECK_TYPE_SIZE(ifaddrs);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
......@@ -1086,11 +1092,13 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo));
#endif
#if !SANITIZER_ANDROID
CHECK_TYPE_SIZE(timeb);
CHECK_SIZE_AND_OFFSET(timeb, time);
CHECK_SIZE_AND_OFFSET(timeb, millitm);
CHECK_SIZE_AND_OFFSET(timeb, timezone);
CHECK_SIZE_AND_OFFSET(timeb, dstflag);
#endif
CHECK_TYPE_SIZE(passwd);
CHECK_SIZE_AND_OFFSET(passwd, pw_name);
......
......@@ -37,11 +37,11 @@ namespace __sanitizer {
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
extern unsigned struct_sched_param_sz;
extern unsigned struct_statfs_sz;
extern unsigned struct_statfs64_sz;
extern unsigned struct_sockaddr_sz;
#if !SANITIZER_ANDROID
extern unsigned struct_statfs_sz;
extern unsigned struct_sockaddr_sz;
extern unsigned ucontext_t_sz;
#endif // !SANITIZER_ANDROID
......@@ -65,6 +65,13 @@ namespace __sanitizer {
#elif defined(__powerpc64__)
const unsigned struct_kernel_stat_sz = 144;
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__mips__)
#if SANITIZER_WORDSIZE == 64
const unsigned struct_kernel_stat_sz = 216;
#else
const unsigned struct_kernel_stat_sz = 144;
#endif
const unsigned struct_kernel_stat64_sz = 104;
#endif
struct __sanitizer_perf_event_attr {
unsigned type;
......@@ -160,6 +167,12 @@ namespace __sanitizer {
unsigned __seq;
u64 __unused1;
u64 __unused2;
#elif defined(__mips__)
unsigned int mode;
unsigned short __seq;
unsigned short __pad1;
unsigned long __unused1;
unsigned long __unused2;
#else
unsigned short mode;
unsigned short __pad1;
......@@ -188,15 +201,15 @@ namespace __sanitizer {
u64 shm_ctime;
#else
uptr shm_atime;
#ifndef _LP64
#if !defined(_LP64) && !defined(__mips__)
uptr __unused1;
#endif
uptr shm_dtime;
#ifndef _LP64
#if !defined(_LP64) && !defined(__mips__)
uptr __unused2;
#endif
uptr shm_ctime;
#ifndef _LP64
#if !defined(_LP64) && !defined(__mips__)
uptr __unused3;
#endif
#endif
......@@ -438,8 +451,13 @@ namespace __sanitizer {
typedef long __sanitizer_clock_t;
#endif
#if SANITIZER_LINUX
typedef int __sanitizer_clockid_t;
#endif
#if SANITIZER_LINUX || SANITIZER_FREEBSD
#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)
#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\
|| defined(__mips__)
typedef unsigned __sanitizer___kernel_uid_t;
typedef unsigned __sanitizer___kernel_gid_t;
#else
......@@ -452,7 +470,7 @@ namespace __sanitizer {
typedef long __sanitizer___kernel_off_t;
#endif
#if defined(__powerpc__) || defined(__aarch64__)
#if defined(__powerpc__) || defined(__aarch64__) || defined(__mips__)
typedef unsigned int __sanitizer___kernel_old_uid_t;
typedef unsigned int __sanitizer___kernel_old_gid_t;
#else
......@@ -492,6 +510,9 @@ namespace __sanitizer {
// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
struct __sanitizer_sigaction {
#if defined(__mips__) && !SANITIZER_FREEBSD
unsigned int sa_flags;
#endif
union {
void (*sigaction)(int sig, void *siginfo, void *uctx);
void (*handler)(int sig);
......@@ -501,11 +522,16 @@ namespace __sanitizer {
__sanitizer_sigset_t sa_mask;
#else
__sanitizer_sigset_t sa_mask;
#ifndef __mips__
int sa_flags;
#endif
#endif
#if SANITIZER_LINUX
void (*sa_restorer)();
#endif
#if defined(__mips__) && (SANITIZER_WORDSIZE == 32)
int sa_resv[1];
#endif
};
#if SANITIZER_FREEBSD
......@@ -676,6 +702,7 @@ namespace __sanitizer {
extern int ptrace_setsiginfo;
extern int ptrace_getregset;
extern int ptrace_setregset;
extern int ptrace_geteventmsg;
#endif
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
......@@ -718,7 +745,7 @@ struct __sanitizer_obstack {
#define IOC_NRBITS 8
#define IOC_TYPEBITS 8
#if defined(__powerpc__) || defined(__powerpc64__)
#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
#define IOC_SIZEBITS 13
#define IOC_DIRBITS 3
#define IOC_NONE 1U
......@@ -832,7 +859,7 @@ struct __sanitizer_obstack {
// A special value to mark ioctls that are not present on the target platform,
// when it can not be determined without including any system headers.
extern unsigned IOCTL_NOT_PRESENT;
extern const unsigned IOCTL_NOT_PRESENT;
extern unsigned IOCTL_FIOASYNC;
extern unsigned IOCTL_FIOCLEX;
......
......@@ -204,6 +204,17 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
return internal_iserror(map) ? 0 : (void *)map;
}
void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
uptr flags = MAP_SHARED;
if (addr) flags |= MAP_FIXED;
uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
if (internal_iserror(p)) {
Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset,
size, p);
return 0;
}
return (void *)p;
}
static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
uptr start2, uptr end2) {
......
......@@ -42,30 +42,49 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
madvise((void*)addr, size, MADV_DONTNEED);
}
void DisableCoreDumper() {
struct rlimit nocore;
nocore.rlim_cur = 0;
nocore.rlim_max = 0;
setrlimit(RLIMIT_CORE, &nocore);
static rlim_t getlim(int res) {
rlimit rlim;
CHECK_EQ(0, getrlimit(res, &rlim));
return rlim.rlim_cur;
}
static void setlim(int res, rlim_t lim) {
// The following magic is to prevent clang from replacing it with memset.
volatile struct rlimit rlim;
rlim.rlim_cur = lim;
rlim.rlim_max = lim;
if (setrlimit(res, (struct rlimit*)&rlim)) {
Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
}
void DisableCoreDumperIfNecessary() {
if (common_flags()->disable_coredump) {
setlim(RLIMIT_CORE, 0);
}
}
bool StackSizeIsUnlimited() {
struct rlimit rlim;
CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
return ((uptr)rlim.rlim_cur == (uptr)-1);
rlim_t stack_size = getlim(RLIMIT_STACK);
return (stack_size == RLIM_INFINITY);
}
void SetStackSizeLimitInBytes(uptr limit) {
struct rlimit rlim;
rlim.rlim_cur = limit;
rlim.rlim_max = limit;
if (setrlimit(RLIMIT_STACK, &rlim)) {
Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
setlim(RLIMIT_STACK, (rlim_t)limit);
CHECK(!StackSizeIsUnlimited());
}
bool AddressSpaceIsUnlimited() {
rlim_t as_size = getlim(RLIMIT_AS);
return (as_size == RLIM_INFINITY);
}
void SetAddressSpaceUnlimited() {
setlim(RLIMIT_AS, RLIM_INFINITY);
CHECK(AddressSpaceIsUnlimited());
}
void SleepForSeconds(int seconds) {
sleep(seconds);
}
......@@ -127,7 +146,9 @@ static void MaybeInstallSigaction(int signum,
struct sigaction sigact;
internal_memset(&sigact, 0, sizeof(sigact));
sigact.sa_sigaction = (sa_sigaction_t)handler;
sigact.sa_flags = SA_SIGINFO;
// Do not block the signal from being received in that signal's handler.
// Clients are responsible for handling this correctly.
sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
VReport(1, "Installed the sigaction for signal %d\n", signum);
......@@ -143,6 +164,28 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
}
#endif // SANITIZER_GO
bool IsAccessibleMemoryRange(uptr beg, uptr size) {
uptr page_size = GetPageSizeCached();
// Checking too large memory ranges is slow.
CHECK_LT(size, page_size * 10);
int sock_pair[2];
if (pipe(sock_pair))
return false;
uptr bytes_written =
internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
int write_errno;
bool result;
if (internal_iserror(bytes_written, &write_errno)) {
CHECK_EQ(EFAULT, write_errno);
result = false;
} else {
result = (bytes_written == size);
}
internal_close(sock_pair[0]);
internal_close(sock_pair[1]);
return result;
}
} // namespace __sanitizer
#endif // SANITIZER_POSIX
......@@ -20,7 +20,8 @@
#include <stdio.h>
#include <stdarg.h>
#if SANITIZER_WINDOWS && !defined(va_copy)
#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \
!defined(va_copy)
# define va_copy(dst, src) ((dst) = (src))
#endif
......
......@@ -24,6 +24,9 @@ struct ProcSelfMapsBuff {
uptr mmaped_size;
uptr len;
};
// Reads process memory map in an OS-specific way.
void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
class MemoryMappingLayout {
......@@ -55,7 +58,7 @@ class MemoryMappingLayout {
// platform-specific files.
# if SANITIZER_FREEBSD || SANITIZER_LINUX
ProcSelfMapsBuff proc_self_maps_;
char *current_;
const char *current_;
// Static mappings cache.
static ProcSelfMapsBuff cached_proc_self_maps_;
......@@ -84,6 +87,11 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
// Returns code range for the specified module.
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
bool IsDecimal(char c);
uptr ParseDecimal(const char **p);
bool IsHex(char c);
uptr ParseHex(const char **p);
} // namespace __sanitizer
#endif // SANITIZER_PROCMAPS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment