From 3051d4390b0db3ed6669e8d17fb45edc26ff6fbd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 10 Jan 2024 00:51:02 -0700 Subject: [PATCH 1/5] Compilation: fix tsan error reporting --- src/Compilation.zig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 9dd45d8ced..fdc7d08e98 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3759,13 +3759,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v const named_frame = tracy.namedFrame("libtsan"); defer named_frame.end(); - libtsan.buildTsan(comp, prog_node) catch |err| { - // TODO Surface more error details. - comp.lockAndSetMiscFailure( + libtsan.buildTsan(comp, prog_node) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.SubCompilationFailed => return, // error reported already + else => comp.lockAndSetMiscFailure( .libtsan, "unable to build TSAN library: {s}", .{@errorName(err)}, - ); + ), }; }, .wasi_libc_crt_file => |crt_file| { From 036e9fd479219ed1116fed8c0da89fa5a2829cf9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 10 Jan 2024 00:51:18 -0700 Subject: [PATCH 2/5] libcxx: fix not passing any_sanitize_thread correctly --- src/libcxx.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcxx.zig b/src/libcxx.zig index 8e28c2174d..b563c56f5a 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -153,6 +153,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { .root_strip = strip, .link_libc = true, .lto = comp.config.lto, + .any_sanitize_thread = comp.config.any_sanitize_thread, }); const root_mod = try Module.create(arena, .{ @@ -358,6 +359,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { .link_libc = true, .any_unwind_tables = unwind_tables, .lto = comp.config.lto, + .any_sanitize_thread = comp.config.any_sanitize_thread, }); const root_mod = try Module.create(arena, .{ From 854b88fda0dc6e92399c27f819bb2a0f5c090eb9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 10 Jan 2024 00:59:52 -0700 Subject: [PATCH 3/5] tsan: update rtl files to LLVM 17.0.6 --- lib/tsan/interception/interception.h | 218 ++- lib/tsan/interception/interception_linux.cpp | 16 +- lib/tsan/interception/interception_linux.h | 18 +- lib/tsan/interception/interception_mac.cpp | 4 +- lib/tsan/interception/interception_mac.h | 4 +- .../interception/interception_type_test.cpp | 6 +- lib/tsan/interception/interception_win.cpp | 118 +- lib/tsan/interception/interception_win.h | 5 + lib/tsan/sanitizer_common/sancov_flags.inc | 2 +- .../sanitizer_common/sanitizer_addrhashmap.h | 46 +- .../sanitizer_common/sanitizer_allocator.cpp | 89 +- .../sanitizer_common/sanitizer_allocator.h | 18 +- .../sanitizer_allocator_bytemap.h | 107 -- .../sanitizer_allocator_combined.h | 18 +- .../sanitizer_allocator_dlsym.h | 79 + .../sanitizer_allocator_interface.h | 4 + .../sanitizer_allocator_internal.h | 3 +- .../sanitizer_allocator_primary32.h | 23 +- .../sanitizer_allocator_primary64.h | 29 +- .../sanitizer_allocator_report.cpp | 3 +- .../sanitizer_allocator_secondary.h | 18 +- .../sanitizer_allocator_size_class_map.h | 8 +- .../sanitizer_allocator_stats.h | 27 +- .../sanitizer_common/sanitizer_array_ref.h | 123 ++ lib/tsan/sanitizer_common/sanitizer_asm.h | 57 +- .../sanitizer_common/sanitizer_atomic_clang.h | 17 +- .../sanitizer_atomic_clang_mips.h | 2 +- .../sanitizer_chained_origin_depot.cpp | 148 ++ .../sanitizer_chained_origin_depot.h | 46 + .../sanitizer_common/sanitizer_common.cpp | 78 +- lib/tsan/sanitizer_common/sanitizer_common.h | 150 +- .../sanitizer_common_interceptors.inc | 1614 +++++++++-------- .../sanitizer_common_interceptors_format.inc | 26 +- .../sanitizer_common_interceptors_ioctl.inc | 10 +- ...izer_common_interceptors_memintrinsics.inc | 244 +++ ...izer_common_interceptors_netbsd_compat.inc | 4 +- .../sanitizer_common_interface.inc | 10 + .../sanitizer_common_interface_posix.inc | 2 + .../sanitizer_common_libcdep.cpp | 99 +- .../sanitizer_common_nolibc.cpp | 3 +- .../sanitizer_common_syscalls.inc | 1587 +++++++++------- .../sanitizer_coverage_interface.inc | 10 + .../sanitizer_coverage_win_dll_thunk.cpp | 20 + ...zer_coverage_win_dynamic_runtime_thunk.cpp | 26 + ...nitizer_coverage_win_weak_interception.cpp | 23 + .../sanitizer_deadlock_detector.h | 2 +- .../sanitizer_common/sanitizer_dense_map.h | 705 +++++++ .../sanitizer_dense_map_info.h | 282 +++ lib/tsan/sanitizer_common/sanitizer_errno.h | 2 +- .../sanitizer_common/sanitizer_errno_codes.h | 1 + lib/tsan/sanitizer_common/sanitizer_file.cpp | 20 + lib/tsan/sanitizer_common/sanitizer_file.h | 5 +- .../sanitizer_flag_parser.cpp | 4 +- .../sanitizer_common/sanitizer_flag_parser.h | 4 +- lib/tsan/sanitizer_common/sanitizer_flags.inc | 20 +- .../sanitizer_common/sanitizer_flat_map.h | 162 ++ .../sanitizer_common/sanitizer_fuchsia.cpp | 114 +- lib/tsan/sanitizer_common/sanitizer_hash.h | 24 + .../sanitizer_interceptors_ioctl_netbsd.inc | 4 +- .../sanitizer_interface_internal.h | 211 ++- .../sanitizer_internal_defs.h | 91 +- lib/tsan/sanitizer_common/sanitizer_leb128.h | 87 + lib/tsan/sanitizer_common/sanitizer_libc.cpp | 27 +- lib/tsan/sanitizer_common/sanitizer_libc.h | 29 +- .../sanitizer_common/sanitizer_libignore.cpp | 12 +- .../sanitizer_common/sanitizer_libignore.h | 2 +- lib/tsan/sanitizer_common/sanitizer_linux.cpp | 510 ++++-- lib/tsan/sanitizer_common/sanitizer_linux.h | 29 +- .../sanitizer_linux_libcdep.cpp | 141 +- .../sanitizer_common/sanitizer_linux_s390.cpp | 14 +- .../sanitizer_local_address_space_view.h | 2 +- lib/tsan/sanitizer_common/sanitizer_lzw.h | 159 ++ lib/tsan/sanitizer_common/sanitizer_mac.cpp | 435 ++--- lib/tsan/sanitizer_common/sanitizer_mac.h | 21 +- .../sanitizer_mac_libcdep.cpp | 4 +- .../sanitizer_common/sanitizer_mallinfo.h | 38 + .../sanitizer_common/sanitizer_malloc_mac.inc | 22 +- lib/tsan/sanitizer_common/sanitizer_mutex.cpp | 4 +- lib/tsan/sanitizer_common/sanitizer_mutex.h | 285 ++- .../sanitizer_common/sanitizer_openbsd.cpp | 0 .../sanitizer_persistent_allocator.h | 71 - .../sanitizer_common/sanitizer_platform.h | 412 +++-- .../sanitizer_platform_interceptors.h | 87 +- .../sanitizer_platform_limits_freebsd.cpp | 40 +- .../sanitizer_platform_limits_freebsd.h | 236 ++- .../sanitizer_platform_limits_linux.cpp | 59 +- .../sanitizer_platform_limits_netbsd.cpp | 5 +- .../sanitizer_platform_limits_netbsd.h | 5 +- .../sanitizer_platform_limits_posix.cpp | 154 +- .../sanitizer_platform_limits_posix.h | 151 +- .../sanitizer_platform_limits_solaris.cpp | 3 +- .../sanitizer_platform_limits_solaris.h | 3 +- lib/tsan/sanitizer_common/sanitizer_posix.cpp | 30 +- lib/tsan/sanitizer_common/sanitizer_posix.h | 12 +- .../sanitizer_posix_libcdep.cpp | 10 +- .../sanitizer_common/sanitizer_printf.cpp | 37 +- .../sanitizer_common/sanitizer_procmaps.h | 42 +- .../sanitizer_procmaps_bsd.cpp | 16 + .../sanitizer_procmaps_common.cpp | 28 +- .../sanitizer_procmaps_mac.cpp | 108 +- .../sanitizer_procmaps_solaris.cpp | 50 +- .../sanitizer_common/sanitizer_quarantine.h | 29 +- lib/tsan/sanitizer_common/sanitizer_range.cpp | 62 + lib/tsan/sanitizer_common/sanitizer_range.h | 40 + .../sanitizer_redefine_builtins.h | 52 + .../sanitizer_common/sanitizer_ring_buffer.h | 13 +- .../sanitizer_signal_interceptors.inc | 15 +- .../sanitizer_common/sanitizer_solaris.cpp | 22 - lib/tsan/sanitizer_common/sanitizer_solaris.h | 56 + .../sanitizer_stack_store.cpp | 379 ++++ .../sanitizer_common/sanitizer_stack_store.h | 121 ++ .../sanitizer_common/sanitizer_stackdepot.cpp | 257 ++- .../sanitizer_common/sanitizer_stackdepot.h | 39 +- .../sanitizer_stackdepotbase.h | 173 +- .../sanitizer_common/sanitizer_stacktrace.cpp | 16 +- .../sanitizer_common/sanitizer_stacktrace.h | 19 +- .../sanitizer_stacktrace_libcdep.cpp | 15 +- .../sanitizer_stacktrace_printer.cpp | 87 +- .../sanitizer_stacktrace_printer.h | 9 +- .../sanitizer_stacktrace_sparc.cpp | 8 +- ...r.cpp => sanitizer_stoptheworld_fuchsia.h} | 16 +- .../sanitizer_stoptheworld_linux_libcdep.cpp | 14 +- .../sanitizer_stoptheworld_mac.cpp | 19 +- .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 2 +- .../sanitizer_stoptheworld_win.cpp | 175 ++ .../sanitizer_suppressions.cpp | 1 + .../sanitizer_common/sanitizer_symbolizer.cpp | 20 +- .../sanitizer_common/sanitizer_symbolizer.h | 13 +- .../sanitizer_symbolizer_internal.h | 17 +- .../sanitizer_symbolizer_libbacktrace.cpp | 4 +- .../sanitizer_symbolizer_libcdep.cpp | 91 +- .../sanitizer_symbolizer_mac.cpp | 81 +- .../sanitizer_symbolizer_mac.h | 5 +- .../sanitizer_symbolizer_markup.cpp | 6 +- .../sanitizer_symbolizer_posix_libcdep.cpp | 131 +- .../sanitizer_symbolizer_report.cpp | 17 +- .../sanitizer_symbolizer_win.cpp | 18 +- .../sanitizer_syscall_generic.inc | 5 +- .../sanitizer_syscalls_netbsd.inc | 4 +- .../sanitizer_thread_arg_retval.cpp | 94 + .../sanitizer_thread_arg_retval.h | 116 ++ .../sanitizer_thread_registry.cpp | 80 +- .../sanitizer_thread_registry.h | 20 +- .../sanitizer_thread_safety.h | 45 +- .../sanitizer_tls_get_addr.cpp | 53 +- .../sanitizer_common/sanitizer_tls_get_addr.h | 26 +- .../sanitizer_common/sanitizer_type_traits.h | 79 + .../sanitizer_unwind_linux_libcdep.cpp | 8 +- .../sanitizer_common/sanitizer_unwind_win.cpp | 27 +- lib/tsan/sanitizer_common/sanitizer_vector.h | 4 +- lib/tsan/sanitizer_common/sanitizer_win.cpp | 98 +- .../sanitizer_win_dll_thunk.cpp | 101 ++ .../sanitizer_win_dll_thunk.h | 2 +- .../sanitizer_win_dynamic_runtime_thunk.cpp | 26 + .../sanitizer_win_weak_interception.cpp | 94 + lib/tsan/tsan_clock.cpp | 625 ------- lib/tsan/tsan_clock.h | 293 --- lib/tsan/tsan_debugging.cpp | 12 +- lib/tsan/tsan_defs.h | 100 +- lib/tsan/tsan_dense_alloc.h | 140 +- lib/tsan/tsan_dispatch_defs.h | 73 + lib/tsan/tsan_external.cpp | 40 +- lib/tsan/tsan_fd.cpp | 113 +- lib/tsan/tsan_fd.h | 3 +- lib/tsan/tsan_flags.cpp | 21 +- lib/tsan/tsan_flags.inc | 25 +- lib/tsan/tsan_ignoreset.cpp | 12 +- lib/tsan/tsan_ignoreset.h | 13 +- lib/tsan/tsan_ilist.h | 189 ++ lib/tsan/tsan_interceptors.h | 108 +- lib/tsan/tsan_interceptors_mac.cpp | 11 +- lib/tsan/tsan_interceptors_memintrinsics.cpp | 43 + lib/tsan/tsan_interceptors_posix.cpp | 1058 ++++++----- lib/tsan/tsan_interface.cpp | 99 +- lib/tsan/tsan_interface.h | 22 +- lib/tsan/tsan_interface.inc | 190 ++ lib/tsan/tsan_interface_ann.cpp | 169 +- lib/tsan/tsan_interface_atomic.cpp | 332 ++-- lib/tsan/tsan_interface_inl.h | 133 -- lib/tsan/tsan_interface_java.cpp | 284 ++- lib/tsan/tsan_malloc_mac.cpp | 30 +- lib/tsan/tsan_mman.cpp | 133 +- lib/tsan/tsan_mman.h | 55 +- lib/tsan/tsan_mutexset.cpp | 48 +- lib/tsan/tsan_mutexset.h | 60 +- lib/tsan/tsan_new_delete.cpp | 199 ++ lib/tsan/tsan_platform.h | 1409 ++++++-------- lib/tsan/tsan_platform_linux.cpp | 157 +- lib/tsan/tsan_platform_mac.cpp | 277 ++- lib/tsan/tsan_platform_posix.cpp | 51 +- lib/tsan/tsan_platform_windows.cpp | 33 + lib/tsan/tsan_report.cpp | 108 +- lib/tsan/tsan_report.h | 43 +- lib/tsan/tsan_rtl.cpp | 1356 +++++++------- lib/tsan/tsan_rtl.h | 801 ++++---- lib/tsan/tsan_rtl_aarch64.S | 37 +- lib/tsan/tsan_rtl_access.cpp | 744 ++++++++ lib/tsan/tsan_rtl_amd64.S | 164 +- lib/tsan/tsan_rtl_mutex.cpp | 721 ++++---- lib/tsan/tsan_rtl_proc.cpp | 1 - lib/tsan/tsan_rtl_report.cpp | 690 ++++--- lib/tsan/tsan_rtl_thread.cpp | 455 ++--- lib/tsan/tsan_shadow.h | 193 ++ lib/tsan/tsan_spinlock_defs_mac.h | 45 + lib/tsan/tsan_stack_trace.cpp | 12 +- lib/tsan/tsan_suppressions.cpp | 5 +- lib/tsan/tsan_symbolize.cpp | 3 +- lib/tsan/tsan_sync.cpp | 132 +- lib/tsan/tsan_sync.h | 80 +- lib/tsan/tsan_trace.h | 217 ++- lib/tsan/tsan_update_shadow_word_inl.h | 59 - lib/tsan/tsan_vector_clock.cpp | 126 ++ lib/tsan/tsan_vector_clock.h | 51 + 213 files changed, 15760 insertions(+), 9960 deletions(-) delete mode 100644 lib/tsan/sanitizer_common/sanitizer_allocator_bytemap.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_allocator_dlsym.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_array_ref.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_chained_origin_depot.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_chained_origin_depot.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc create mode 100644 lib/tsan/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_dense_map.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_dense_map_info.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_flat_map.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_leb128.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_lzw.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_mallinfo.h delete mode 100644 lib/tsan/sanitizer_common/sanitizer_openbsd.cpp delete mode 100644 lib/tsan/sanitizer_common/sanitizer_persistent_allocator.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_range.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_range.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_redefine_builtins.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_solaris.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_stack_store.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stack_store.h rename lib/tsan/sanitizer_common/{sanitizer_persistent_allocator.cpp => sanitizer_stoptheworld_fuchsia.h} (52%) create mode 100644 lib/tsan/sanitizer_common/sanitizer_stoptheworld_win.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_thread_arg_retval.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_thread_arg_retval.h create mode 100644 lib/tsan/sanitizer_common/sanitizer_win_dll_thunk.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_win_weak_interception.cpp delete mode 100644 lib/tsan/tsan_clock.cpp delete mode 100644 lib/tsan/tsan_clock.h create mode 100644 lib/tsan/tsan_dispatch_defs.h create mode 100644 lib/tsan/tsan_ilist.h create mode 100644 lib/tsan/tsan_interceptors_memintrinsics.cpp create mode 100644 lib/tsan/tsan_interface.inc delete mode 100644 lib/tsan/tsan_interface_inl.h create mode 100644 lib/tsan/tsan_new_delete.cpp create mode 100644 lib/tsan/tsan_platform_windows.cpp create mode 100644 lib/tsan/tsan_rtl_access.cpp create mode 100644 lib/tsan/tsan_shadow.h create mode 100644 lib/tsan/tsan_spinlock_defs_mac.h delete mode 100644 lib/tsan/tsan_update_shadow_word_inl.h create mode 100644 lib/tsan/tsan_vector_clock.cpp create mode 100644 lib/tsan/tsan_vector_clock.h diff --git a/lib/tsan/interception/interception.h b/lib/tsan/interception/interception.h index d8dc092c45..069f73d276 100644 --- a/lib/tsan/interception/interception.h +++ b/lib/tsan/interception/interception.h @@ -14,9 +14,10 @@ #ifndef INTERCEPTION_H #define INTERCEPTION_H +#include "sanitizer_common/sanitizer_asm.h" #include "sanitizer_common/sanitizer_internal_defs.h" -#if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ +#if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE && \ !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \ !SANITIZER_SOLARIS # error "Interception doesn't work on this operating system." @@ -67,28 +68,54 @@ typedef __sanitizer::OFF64_T OFF64_T; // for more details). To intercept such functions you need to use the // INTERCEPTOR_WITH_SUFFIX(...) macro. -// How it works: -// To replace system functions on Linux we just need to declare functions -// with same names in our library and then obtain the real function pointers -// using dlsym(). -// There is one complication. A user may also intercept some of the functions -// we intercept. To resolve this we declare our interceptors with __interceptor_ -// prefix, and then make actual interceptors weak aliases to __interceptor_ -// functions. +// How it works on Linux +// --------------------- +// +// To replace system functions on Linux we just need to declare functions with +// the same names in our library and then obtain the real function pointers +// using dlsym(). +// +// There is one complication: a user may also intercept some of the functions we +// intercept. To allow for up to 3 interceptors (including ours) of a given +// function "func", the interceptor implementation is in ___interceptor_func, +// which is aliased by a weak function __interceptor_func, which in turn is +// aliased (via a trampoline) by weak wrapper function "func". +// +// Most user interceptors should define a foreign interceptor as follows: +// +// - provide a non-weak function "func" that performs interception; +// - if __interceptor_func exists, call it to perform the real functionality; +// - if it does not exist, figure out the real function and call it instead. +// +// In rare cases, a foreign interceptor (of another dynamic analysis runtime) +// may be defined as follows (on supported architectures): +// +// - provide a non-weak function __interceptor_func that performs interception; +// - if ___interceptor_func exists, call it to perform the real functionality; +// - if it does not exist, figure out the real function and call it instead; +// - provide a weak function "func" that is an alias to __interceptor_func. +// +// With this protocol, sanitizer interceptors, foreign user interceptors, and +// foreign interceptors of other dynamic analysis runtimes, or any combination +// thereof, may co-exist simultaneously. +// +// How it works on Mac OS +// ---------------------- +// +// This is not so on Mac OS, where the two-level namespace makes our replacement +// functions invisible to other libraries. This may be overcomed using the +// DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared libraries in +// Chromium were noticed when doing so. // -// This is not so on Mac OS, where the two-level namespace makes -// our replacement functions invisible to other libraries. This may be overcomed -// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared -// libraries in Chromium were noticed when doing so. // Instead we create a dylib containing a __DATA,__interpose section that // associates library functions with their wrappers. When this dylib is -// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all -// the calls to interposed functions done through stubs to the wrapper -// functions. +// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all the +// calls to interposed functions done through stubs to the wrapper functions. +// // As it's decided at compile time which functions are to be intercepted on Mac, // INTERCEPT_FUNCTION() is effectively a no-op on this system. -#if SANITIZER_MAC +#if SANITIZER_APPLE #include // For __DARWIN_ALIAS_C(). // Just a pair of pointers. @@ -100,53 +127,102 @@ struct interpose_substitution { // For a function foo() create a global pair of pointers { wrap_foo, foo } in // the __DATA,__interpose section. // As a result all the calls to foo() will be routed to wrap_foo() at runtime. -#define INTERPOSER(func_name) __attribute__((used)) \ +#define INTERPOSER(func_name) __attribute__((used)) \ const interpose_substitution substitution_##func_name[] \ __attribute__((section("__DATA, __interpose"))) = { \ - { reinterpret_cast(WRAP(func_name)), \ - reinterpret_cast(func_name) } \ + { reinterpret_cast(WRAP(func_name)), \ + reinterpret_cast(func_name) } \ } // For a function foo() and a wrapper function bar() create a global pair // of pointers { bar, foo } in the __DATA,__interpose section. // As a result all the calls to foo() will be routed to bar() at runtime. #define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \ -const interpose_substitution substitution_##func_name[] \ - __attribute__((section("__DATA, __interpose"))) = { \ - { reinterpret_cast(wrapper_name), \ - reinterpret_cast(func_name) } \ +const interpose_substitution substitution_##func_name[] \ + __attribute__((section("__DATA, __interpose"))) = { \ + { reinterpret_cast(wrapper_name), \ + reinterpret_cast(func_name) } \ } # define WRAP(x) wrap_##x -# define WRAPPER_NAME(x) "wrap_"#x +# define TRAMPOLINE(x) WRAP(x) # define INTERCEPTOR_ATTRIBUTE # define DECLARE_WRAPPER(ret_type, func, ...) #elif SANITIZER_WINDOWS # define WRAP(x) __asan_wrap_##x -# define WRAPPER_NAME(x) "__asan_wrap_"#x +# define TRAMPOLINE(x) WRAP(x) # define INTERCEPTOR_ATTRIBUTE __declspec(dllexport) -# define DECLARE_WRAPPER(ret_type, func, ...) \ +# define DECLARE_WRAPPER(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__); -# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ +# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); -#elif SANITIZER_FREEBSD || SANITIZER_NETBSD -# define WRAP(x) __interceptor_ ## x -# define WRAPPER_NAME(x) "__interceptor_" #x +#elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) +# if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT +// Weak aliases of weak aliases do not work, therefore we need to set up a +// trampoline function. The function "func" is a weak alias to the trampoline +// (so that we may check if "func" was overridden), which calls the weak +// function __interceptor_func, which in turn aliases the actual interceptor +// implementation ___interceptor_func: +// +// [wrapper "func": weak] --(alias)--> [TRAMPOLINE(func)] +// | +// +--------(tail call)-------+ +// | +// v +// [__interceptor_func: weak] --(alias)--> [WRAP(func)] +// +// We use inline assembly to define most of this, because not all compilers +// support functions with the "naked" attribute with every architecture. +# define WRAP(x) ___interceptor_ ## x +# define TRAMPOLINE(x) __interceptor_trampoline_ ## x +# if SANITIZER_FREEBSD || SANITIZER_NETBSD // 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"))); -#elif !SANITIZER_FUCHSIA -# define WRAP(x) __interceptor_ ## x -# define WRAPPER_NAME(x) "__interceptor_" #x -# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) -# define DECLARE_WRAPPER(ret_type, func, ...) \ - extern "C" ret_type func(__VA_ARGS__) \ - __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); +# define __ASM_WEAK_WRAPPER(func) ".globl " #func "\n" +# else +# define __ASM_WEAK_WRAPPER(func) ".weak " #func "\n" +# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD +// Keep trampoline implementation in sync with sanitizer_common/sanitizer_asm.h +# define DECLARE_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__); \ + extern "C" ret_type TRAMPOLINE(func)(__VA_ARGS__); \ + extern "C" ret_type __interceptor_##func(__VA_ARGS__) \ + INTERCEPTOR_ATTRIBUTE __attribute__((weak)) ALIAS(WRAP(func)); \ + asm( \ + ".text\n" \ + __ASM_WEAK_WRAPPER(func) \ + ".set " #func ", " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ + ".globl " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ + ".type " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", %function\n" \ + SANITIZER_STRINGIFY(TRAMPOLINE(func)) ":\n" \ + SANITIZER_STRINGIFY(CFI_STARTPROC) "\n" \ + SANITIZER_STRINGIFY(ASM_TAIL_CALL) " __interceptor_" \ + SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(func)) "\n" \ + SANITIZER_STRINGIFY(CFI_ENDPROC) "\n" \ + ".size " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \ + ".-" SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ + ); +# else // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT +// Some architectures cannot implement efficient interceptor trampolines with +// just a plain jump due to complexities of resolving a preemptible symbol. In +// those cases, revert to just this scheme: +// +// [wrapper "func": weak] --(alias)--> [WRAP(func)] +// +# define WRAP(x) __interceptor_ ## x +# define TRAMPOLINE(x) WRAP(x) +# if SANITIZER_FREEBSD || SANITIZER_NETBSD +# define __ATTRIBUTE_WEAK_WRAPPER +# else +# define __ATTRIBUTE_WEAK_WRAPPER __attribute__((weak)) +# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD +# define DECLARE_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__) \ + INTERCEPTOR_ATTRIBUTE __ATTRIBUTE_WEAK_WRAPPER ALIAS(WRAP(func)); +# endif // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT #endif #if SANITIZER_FUCHSIA @@ -157,33 +233,35 @@ const interpose_substitution substitution_##func_name[] \ # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define REAL(x) __unsanitized_##x # define DECLARE_REAL(ret_type, func, ...) -#elif !SANITIZER_MAC +#elif !SANITIZER_APPLE # define PTR_TO_REAL(x) real_##x # define REAL(x) __interception::PTR_TO_REAL(x) # define FUNC_TYPE(x) x##_type -# define DECLARE_REAL(ret_type, func, ...) \ +# define DECLARE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ - namespace __interception { \ - extern FUNC_TYPE(func) PTR_TO_REAL(func); \ + namespace __interception { \ + extern FUNC_TYPE(func) PTR_TO_REAL(func); \ } # define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) -#else // SANITIZER_MAC +#else // SANITIZER_APPLE # define REAL(x) x # define DECLARE_REAL(ret_type, func, ...) \ extern "C" ret_type func(__VA_ARGS__); # define ASSIGN_REAL(x, y) -#endif // SANITIZER_MAC +#endif // SANITIZER_APPLE #if !SANITIZER_FUCHSIA -# define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ +# define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ DECLARE_REAL(ret_type, func, __VA_ARGS__) \ + extern "C" ret_type TRAMPOLINE(func)(__VA_ARGS__); \ extern "C" ret_type WRAP(func)(__VA_ARGS__); // Declare an interceptor and its wrapper defined in a different translation // unit (ex. asm). -# define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) \ - extern "C" ret_type WRAP(func)(__VA_ARGS__); \ - extern "C" ret_type func(__VA_ARGS__); +# define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type TRAMPOLINE(func)(__VA_ARGS__); \ + extern "C" ret_type WRAP(func)(__VA_ARGS__); \ + extern "C" ret_type func(__VA_ARGS__); #else # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) @@ -193,7 +271,7 @@ const interpose_substitution substitution_##func_name[] \ // macros does its job. In exceptional cases you may need to call REAL(foo) // without defining INTERCEPTOR(..., foo, ...). For example, if you override // foo with an interceptor for other function. -#if !SANITIZER_MAC && !SANITIZER_FUCHSIA +#if !SANITIZER_APPLE && !SANITIZER_FUCHSIA # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -213,25 +291,23 @@ const interpose_substitution substitution_##func_name[] \ __interceptor_##func(__VA_ARGS__); \ extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__) -#elif !SANITIZER_MAC +#elif !SANITIZER_APPLE -#define INTERCEPTOR(ret_type, func, ...) \ - DEFINE_REAL(ret_type, func, __VA_ARGS__) \ - DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ - extern "C" \ - INTERCEPTOR_ATTRIBUTE \ - ret_type WRAP(func)(__VA_ARGS__) +#define INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__) \ + DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ + extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__) // We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now. #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ INTERCEPTOR(ret_type, func, __VA_ARGS__) -#else // SANITIZER_MAC +#else // SANITIZER_APPLE -#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \ - extern "C" ret_type func(__VA_ARGS__) suffix; \ - extern "C" ret_type WRAP(func)(__VA_ARGS__); \ - INTERPOSER(func); \ +#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__) suffix; \ + extern "C" ret_type WRAP(func)(__VA_ARGS__); \ + INTERPOSER(func); \ extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__) #define INTERCEPTOR(ret_type, func, ...) \ @@ -246,14 +322,12 @@ const interpose_substitution substitution_##func_name[] \ #endif #if SANITIZER_WINDOWS -# define INTERCEPTOR_WINAPI(ret_type, func, ...) \ +# define INTERCEPTOR_WINAPI(ret_type, func, ...) \ typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \ - namespace __interception { \ - FUNC_TYPE(func) PTR_TO_REAL(func); \ - } \ - extern "C" \ - INTERCEPTOR_ATTRIBUTE \ - ret_type __stdcall WRAP(func)(__VA_ARGS__) + namespace __interception { \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ + } \ + extern "C" INTERCEPTOR_ATTRIBUTE ret_type __stdcall WRAP(func)(__VA_ARGS__) #endif // ISO C++ forbids casting between pointer-to-function and pointer-to-object, @@ -278,7 +352,7 @@ typedef unsigned long uptr; # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) -#elif SANITIZER_MAC +#elif SANITIZER_APPLE # include "interception_mac.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) # define INTERCEPT_FUNCTION_VER(func, symver) \ diff --git a/lib/tsan/interception/interception_linux.cpp b/lib/tsan/interception/interception_linux.cpp index 5111a87f0a..ef8136eb4f 100644 --- a/lib/tsan/interception/interception_linux.cpp +++ b/lib/tsan/interception/interception_linux.cpp @@ -33,7 +33,7 @@ static int StrCmp(const char *s1, const char *s2) { } #endif -static void *GetFuncAddr(const char *name, uptr wrapper_addr) { +static void *GetFuncAddr(const char *name, uptr trampoline) { #if SANITIZER_NETBSD // FIXME: Find a better way to handle renames if (StrCmp(name, "sigaction")) @@ -50,17 +50,17 @@ static void *GetFuncAddr(const char *name, uptr wrapper_addr) { // In case `name' is not loaded, dlsym ends up finding the actual wrapper. // We don't want to intercept the wrapper and have it point to itself. - if ((uptr)addr == wrapper_addr) + if ((uptr)addr == trampoline) addr = nullptr; } return addr; } bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, - uptr wrapper) { - void *addr = GetFuncAddr(name, wrapper); + uptr trampoline) { + void *addr = GetFuncAddr(name, trampoline); *ptr_to_real = (uptr)addr; - return addr && (func == wrapper); + return addr && (func == trampoline); } // dlvsym is a GNU extension supported by some other platforms. @@ -70,12 +70,12 @@ static void *GetFuncAddr(const char *name, const char *ver) { } bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, - uptr func, uptr wrapper) { + uptr func, uptr trampoline) { void *addr = GetFuncAddr(name, ver); *ptr_to_real = (uptr)addr; - return addr && (func == wrapper); + return addr && (func == trampoline); } -#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD +# endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD } // namespace __interception diff --git a/lib/tsan/interception/interception_linux.h b/lib/tsan/interception/interception_linux.h index a08f8cb98c..433a3d9bd7 100644 --- a/lib/tsan/interception/interception_linux.h +++ b/lib/tsan/interception/interception_linux.h @@ -15,7 +15,7 @@ SANITIZER_SOLARIS #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) -# error "interception_linux.h should be included from interception library only" +# error interception_linux.h should be included from interception library only #endif #ifndef INTERCEPTION_LINUX_H @@ -23,26 +23,26 @@ namespace __interception { bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, - uptr wrapper); + uptr trampoline); bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, - uptr func, uptr wrapper); + uptr func, uptr trampoline); } // namespace __interception #define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ ::__interception::InterceptFunction( \ #func, \ - (::__interception::uptr *) & REAL(func), \ - (::__interception::uptr) & (func), \ - (::__interception::uptr) & WRAP(func)) + (::__interception::uptr *)&REAL(func), \ + (::__interception::uptr)&(func), \ + (::__interception::uptr)&TRAMPOLINE(func)) // dlvsym is a GNU extension supported by some other platforms. #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ ::__interception::InterceptFunction( \ #func, symver, \ - (::__interception::uptr *) & REAL(func), \ - (::__interception::uptr) & (func), \ - (::__interception::uptr) & WRAP(func)) + (::__interception::uptr *)&REAL(func), \ + (::__interception::uptr)&(func), \ + (::__interception::uptr)&TRAMPOLINE(func)) #else #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/lib/tsan/interception/interception_mac.cpp b/lib/tsan/interception/interception_mac.cpp index fb6eadcff5..03eae0fdca 100644 --- a/lib/tsan/interception/interception_mac.cpp +++ b/lib/tsan/interception/interception_mac.cpp @@ -13,6 +13,6 @@ #include "interception.h" -#if SANITIZER_MAC +#if SANITIZER_APPLE -#endif // SANITIZER_MAC +#endif // SANITIZER_APPLE diff --git a/lib/tsan/interception/interception_mac.h b/lib/tsan/interception/interception_mac.h index eddedb8959..26079518c6 100644 --- a/lib/tsan/interception/interception_mac.h +++ b/lib/tsan/interception/interception_mac.h @@ -11,7 +11,7 @@ // Mac-specific interception methods. //===----------------------------------------------------------------------===// -#if SANITIZER_MAC +#if SANITIZER_APPLE #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_mac.h should be included from interception.h only" @@ -24,4 +24,4 @@ #define INTERCEPT_FUNCTION_VER_MAC(func, symver) #endif // INTERCEPTION_MAC_H -#endif // SANITIZER_MAC +#endif // SANITIZER_APPLE diff --git a/lib/tsan/interception/interception_type_test.cpp b/lib/tsan/interception/interception_type_test.cpp index a611604a70..7c3de82a1e 100644 --- a/lib/tsan/interception/interception_type_test.cpp +++ b/lib/tsan/interception/interception_type_test.cpp @@ -13,7 +13,7 @@ #include "interception.h" -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_APPLE #include #include @@ -24,9 +24,9 @@ COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t)); COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t)); COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t)); -#if !SANITIZER_MAC +# if SANITIZER_GLIBC || SANITIZER_ANDROID COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t)); -#endif +# endif // The following are the cases when pread (and friends) is used instead of // pread64. In those cases we need OFF_T to match off_t. We don't care about the diff --git a/lib/tsan/interception/interception_win.cpp b/lib/tsan/interception/interception_win.cpp index 98bc756ae5..00c317510e 100644 --- a/lib/tsan/interception/interception_win.cpp +++ b/lib/tsan/interception/interception_win.cpp @@ -56,7 +56,7 @@ // tramp: jmp QWORD [addr] // addr: .bytes // -// Note: is equilavent to