Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASAN improvements #41675

Merged
merged 4 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cli/loader_exe.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ extern "C" {

JULIA_DEFINE_FAST_TLS

#ifdef _COMPILER_ASAN_ENABLED_
JL_DLLEXPORT const char* __asan_default_options()
{
return "allow_user_segv_handler=1:detect_leaks=0";
// FIXME: enable LSAN after fixing leaks & defining __lsan_default_suppressions(),
// or defining __lsan_default_options = exitcode=0 once publicly available
// (here and in flisp/flmain.c)
}
#endif

#ifdef _OS_WINDOWS_
int mainCRTStartup(void)
{
Expand All @@ -25,6 +35,12 @@ int main(int argc, char * argv[])
{
#endif

#ifdef _COMPILER_ASAN_ENABLED_
// ASAN does not support RTLD_DEEPBIND
// https://github.com/google/sanitizers/issues/611
putenv("LBT_USE_RTLD_DEEPBIND=0");
#endif

// Convert Windows wchar_t values to UTF8
#ifdef _OS_WINDOWS_
for (int i = 0; i < argc; i++) {
Expand Down
3 changes: 0 additions & 3 deletions contrib/asan/Make.user.asan
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,3 @@ override JULIA_BUILD_MODE=debug

# make ASAN consume less memory
export ASAN_OPTIONS=detect_leaks=0:fast_unwind_on_malloc=0:allow_user_segv_handler=1:malloc_context_size=2

# tell libblastrampoline to not use RTLD_DEEPBIND
export LBT_USE_RTLD_DEEPBIND=0
maleadt marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 1 addition & 6 deletions contrib/asan/check.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,7 @@ function main(args = ARGS)::Int
timeout = Threads.Atomic{Bool}(false)
isstarted = false
mktemp() do tmppath, tmpio
cmd = addenv(
`$julia -e $code $tmppath`,
"ASAN_OPTIONS" =>
"detect_leaks=0:fast_unwind_on_malloc=0:allow_user_segv_handler=1:malloc_context_size=2",
"LBT_USE_RTLD_DEEPBIND" => "0",
maleadt marked this conversation as resolved.
Show resolved Hide resolved
)
cmd = `$julia -e $code $tmppath`
# Note: Ideally, we set ASAN_SYMBOLIZER_PATH here. But there is no easy
# way to find out the path from just a Julia binary.

Expand Down
12 changes: 6 additions & 6 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,13 +664,13 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(createLowerSimdLoopPass()); // Annotate loop marked with "loopinfo" as LLVM parallel loop
if (dump_native)
PM->add(createMultiVersioningPass());
#if defined(JL_ASAN_ENABLED)
#if defined(_COMPILER_ASAN_ENABLED_)
PM->add(createAddressSanitizerFunctionPass());
#endif
#if defined(JL_MSAN_ENABLED)
#if defined(_COMPILER_MSAN_ENABLED_)
PM->add(createMemorySanitizerPass(true));
#endif
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
PM->add(createThreadSanitizerLegacyPassPass());
#endif
return;
Expand Down Expand Up @@ -813,13 +813,13 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
}
PM->add(createCombineMulAddPass());
PM->add(createDivRemPairsPass());
#if defined(JL_ASAN_ENABLED)
#if defined(_COMPILER_ASAN_ENABLED_)
PM->add(createAddressSanitizerFunctionPass());
#endif
#if defined(JL_MSAN_ENABLED)
#if defined(_COMPILER_MSAN_ENABLED_)
PM->add(createMemorySanitizerPass(true));
#endif
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
PM->add(createThreadSanitizerLegacyPassPass());
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion src/atomics.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ enum jl_memory_order {
__atomic_load_n(obj, __ATOMIC_SEQ_CST)
# define jl_atomic_load_acquire(obj) \
__atomic_load_n(obj, __ATOMIC_ACQUIRE)
#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
// For the sake of tsan, call these loads consume ordering since they will act
// as such on the processors we support while normally, the compiler would
// upgrade this to acquire ordering, which is strong (and slower) than we want.
Expand Down
4 changes: 2 additions & 2 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1776,7 +1776,7 @@ static void jl_init_function(Function *F)
#ifdef JL_DISABLE_FPO
F->addFnAttr("frame-pointer", "all");
#endif
#if !defined(JL_ASAN_ENABLED) && !defined(_OS_WINDOWS_)
#if !defined(_COMPILER_ASAN_ENABLED_) && !defined(_OS_WINDOWS_)
// ASAN won't like us accessing undefined memory causing spurious issues,
// and Windows has platform-specific handling which causes it to mishandle
// this annotation. Other platforms should just ignore this if they don't
Expand Down Expand Up @@ -6343,7 +6343,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
f->addFnAttr(Attribute::StackProtectStrong);
#endif

#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
// TODO: enable this only when a argument like `-race` is passed to Julia
// add a macro for no_sanitize_thread
f->addFnAttr(llvm::Attribute::SanitizeThread);
Expand Down
2 changes: 1 addition & 1 deletion src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI
#ifdef RTLD_NOLOAD
| JL_RTLD(flags, NOLOAD)
#endif
#if defined(RTLD_DEEPBIND) && !(defined(JL_ASAN_ENABLED) || defined(JL_TSAN_ENABLED) || defined(JL_MSAN_ENABLED))
#if defined(RTLD_DEEPBIND) && !(defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_TSAN_ENABLED_) || defined(_COMPILER_MSAN_ENABLED_))
| JL_RTLD(flags, DEEPBIND)
#endif
#ifdef RTLD_FIRST
Expand Down
2 changes: 1 addition & 1 deletion src/gc-stacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ void sweep_stack_pools(void)
t->stkbuf = NULL;
_jl_free_stack(ptls2, stkbuf, bufsz);
}
#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
if (t->ctx.tsan_state) {
__tsan_destroy_fiber(t->ctx.tsan_state);
t->ctx.tsan_state = NULL;
Expand Down
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void jl_init_stack_limits(int ismaster, void **stack_lo, void **stack_hi)
static void jl_prep_sanitizers(void)
{
#if !defined(_OS_WINDOWS_)
#if defined(JL_ASAN_ENABLED) || defined(JL_MSAN_ENABLED)
#if defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_MSAN_ENABLED_)
struct rlimit rl;

// When using the sanitizers, increase stack size because they bloat
Expand Down
11 changes: 0 additions & 11 deletions src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,17 +501,6 @@ JL_DLLEXPORT int jl_set_fenv_rounding(int i)
return fesetround(i);
}


#ifdef JL_ASAN_ENABLED
JL_DLLEXPORT const char* __asan_default_options()
{
return "allow_user_segv_handler=1:detect_leaks=0";
// FIXME: enable LSAN after fixing leaks & defining __lsan_default_suppressions(),
// or defining __lsan_default_options = exitcode=0 once publicly available
// (here and in flisp/flmain.c)
}
#endif

static int exec_program(char *program)
{
JL_TRY {
Expand Down
21 changes: 1 addition & 20 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,6 @@
# define JL_THREAD_LOCAL
#endif

#if defined(__has_feature) // Clang flavor
#if __has_feature(address_sanitizer)
#define JL_ASAN_ENABLED
#endif
#if __has_feature(memory_sanitizer)
#define JL_MSAN_ENABLED
#endif
#if __has_feature(thread_sanitizer)
#if __clang_major__ < 11
#error Thread sanitizer runtime libraries in clang < 11 leak memory and cannot be used
#endif
#define JL_TSAN_ENABLED
#endif
#else // GCC flavor
#if defined(__SANITIZE_ADDRESS__)
#define JL_ASAN_ENABLED
#endif
#endif // __has_feature

#define container_of(ptr, type, member) \
((type *) ((char *)(ptr) - offsetof(type, member)))

Expand Down Expand Up @@ -1860,7 +1841,7 @@ typedef struct _jl_task_t {
struct jl_stack_context_t copy_stack_ctx;
#endif
};
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
void *tsan_state;
#endif
void *stkbuf; // malloc'd memory (either copybuf or stack)
Expand Down
6 changes: 3 additions & 3 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifdef JL_ASAN_ENABLED
#ifdef _COMPILER_ASAN_ENABLED_
void __sanitizer_start_switch_fiber(void**, const void*, size_t);
void __sanitizer_finish_switch_fiber(void*, const void**, size_t*);
#endif
#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
void *__tsan_create_fiber(unsigned flags);
void *__tsan_get_current_fiber(void);
void __tsan_destroy_fiber(void *fiber);
Expand Down Expand Up @@ -406,7 +406,7 @@ jl_value_t *jl_permbox64(jl_datatype_t *t, int64_t x);
jl_svec_t *jl_perm_symsvec(size_t n, ...);

// this sizeof(__VA_ARGS__) trick can't be computed until C11, but that only matters to Clang in some situations
#if !defined(__clang_analyzer__) && !(defined(JL_ASAN_ENABLED) || defined(JL_TSAN_ENABLED))
#if !defined(__clang_analyzer__) && !(defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_TSAN_ENABLED_))
#ifdef __GNUC__
#define jl_perm_symsvec(n, ...) \
(jl_perm_symsvec)(__extension__({ \
Expand Down
2 changes: 1 addition & 1 deletion src/julia_threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct jl_stack_context_t {
typedef struct jl_stack_context_t jl_ucontext_t;
#endif
#if defined(JL_HAVE_ASYNCIFY)
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
#error TSAN not currently supported with asyncify
#endif
typedef struct {
Expand Down
12 changes: 5 additions & 7 deletions src/options.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include "platform.h"

#ifndef JL_OPTIONS_H
#define JL_OPTIONS_H

Expand Down Expand Up @@ -158,23 +160,19 @@

// sanitizer defaults ---------------------------------------------------------

#ifndef JULIA_H
#error "Must be included after julia.h"
#endif

// Automatically enable MEMDEBUG and KEEP_BODIES for the sanitizers
#if defined(JL_ASAN_ENABLED) || defined(JL_MSAN_ENABLED)
#if defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_MSAN_ENABLED_)
#define MEMDEBUG
#define KEEP_BODIES
#endif

// TSAN doesn't like COPY_STACKS
#if defined(JL_TSAN_ENABLED) && defined(COPY_STACKS)
#if defined(_COMPILER_TSAN_ENABLED_) && defined(COPY_STACKS)
#undef COPY_STACKS
#endif

// Memory sanitizer needs TLS, which llvm only supports for the small memory model
#if defined(JL_MSAN_ENABLED)
#if defined(_COMPILER_MSAN_ENABLED_)
// todo: fix the llvm MemoryManager to work with small memory model
#endif

Expand Down
19 changes: 19 additions & 0 deletions src/support/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@
#define _COMPILER_GCC_
#endif

#if defined(__has_feature) // Clang flavor
#if __has_feature(address_sanitizer)
#define _COMPILER_ASAN_ENABLED_
#endif
#if __has_feature(memory_sanitizer)
#define _COMPILER_MSAN_ENABLED_
#endif
#if __has_feature(thread_sanitizer)
#if __clang_major__ < 11
#error Thread sanitizer runtime libraries in clang < 11 leak memory and cannot be used
#endif
#define _COMPILER_TSAN_ENABLED_
#endif
#else // GCC flavor
#if defined(__SANITIZE_ADDRESS__)
#define _COMPILER_ASAN_ENABLED_
#endif
#endif // __has_feature

/*******************************************************************************
* OS *
*******************************************************************************/
Expand Down
2 changes: 1 addition & 1 deletion src/support/win32_ucontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ typedef struct {
size_t ss_size;
} uc_stack;
jmp_buf uc_mcontext;
#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
void *tsan_state;
#endif
} win32_ucontext_t;
Expand Down
4 changes: 2 additions & 2 deletions src/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
#include <intrin.h>
#endif

#ifdef JL_MSAN_ENABLED
#ifdef _COMPILER_MSAN_ENABLED_
#include <sanitizer/msan_interface.h>
#endif

Expand Down Expand Up @@ -796,7 +796,7 @@ JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle)

struct link_map *map;
dlinfo(handle, RTLD_DI_LINKMAP, &map);
#ifdef JL_MSAN_ENABLED
#ifdef _COMPILER_MSAN_ENABLED_
__msan_unpoison(&map,sizeof(struct link_map*));
if (map) {
__msan_unpoison(map, sizeof(struct link_map));
Expand Down
18 changes: 9 additions & 9 deletions src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
extern "C" {
#endif

#if defined(JL_ASAN_ENABLED)
#if defined(_COMPILER_ASAN_ENABLED_)
static inline void sanitizer_start_switch_fiber(const void* bottom, size_t size) {
__sanitizer_start_switch_fiber(NULL, bottom, size);
}
Expand All @@ -53,7 +53,7 @@ static inline void sanitizer_start_switch_fiber(const void* bottom, size_t size)
static inline void sanitizer_finish_switch_fiber(void) {}
#endif

#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
static inline void tsan_destroy_ctx(jl_ptls_t ptls, void *state) {
if (state != &ptls->root_task->state) {
__tsan_destroy_fiber(ctx->state);
Expand Down Expand Up @@ -321,7 +321,7 @@ JL_DLLEXPORT jl_task_t *jl_get_next_task(void) JL_NOTSAFEPOINT
return ct;
}

#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
const char tsan_state_corruption[] = "TSAN state corrupted. Exiting HARD!\n";
#endif

Expand All @@ -334,7 +334,7 @@ static void ctx_switch(jl_task_t *lastt)
// none of these locks should be held across a task switch
assert(ptls->locks.len == 0);

#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
if (lastt->ctx.tsan_state != __tsan_get_current_fiber()) {
// Something went really wrong - don't even assume that we can
// use assert/abort which involve lots of signal handling that
Expand Down Expand Up @@ -400,7 +400,7 @@ static void ctx_switch(jl_task_t *lastt)
#endif
jl_set_pgcstack(&t->gcstack);

#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
tsan_switch_to_ctx(&t->tsan_state);
if (killed)
tsan_destroy_ctx(ptls, &lastt->tsan_state);
Expand Down Expand Up @@ -765,7 +765,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion
memcpy(&t->ctx, &ct->ptls->base_ctx, sizeof(t->ctx));
}
#endif
#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
t->tsan_state = __tsan_create_fiber(0);
#endif
return t;
Expand Down Expand Up @@ -1147,7 +1147,7 @@ static void jl_start_fiber_set(jl_ucontext_t *t)
#endif

#if defined(JL_HAVE_SIGALTSTACK)
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
#error TSAN support not currently implemented for this tasking model
#endif

Expand Down Expand Up @@ -1237,7 +1237,7 @@ static void jl_set_fiber(jl_ucontext_t *t)
#endif

#if defined(JL_HAVE_ASYNCIFY)
#if defined(JL_TSAN_ENABLED)
#if defined(_COMPILER_TSAN_ENABLED_)
#error TSAN support not currently implemented for this tasking model
#endif

Expand Down Expand Up @@ -1313,7 +1313,7 @@ void jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi)
jl_set_pgcstack(&ct->gcstack);
assert(jl_current_task == ct);

#ifdef JL_TSAN_ENABLED
#ifdef _COMPILER_TSAN_ENABLED_
ct->tsan_state = __tsan_get_current_fiber();
#endif

Expand Down