diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S --- a/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S +++ b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S @@ -53,6 +53,8 @@ b ASM_WRAPPER_NAME(sigsetjmp) CFI_ENDPROC ASM_SIZE(ASM_WRAPPER_NAME(setjmp_bionic)) + +ASM_INTERCEPTOR_TRAMPOLINE(b, setjmp_bionic) #endif .global ASM_WRAPPER_NAME(sigsetjmp) @@ -79,20 +81,17 @@ CFI_ENDPROC ASM_SIZE(ASM_WRAPPER_NAME(sigsetjmp)) +ASM_INTERCEPTOR_TRAMPOLINE(b, sigsetjmp) -.macro WEAK_ALIAS first second - .weak \second - .equ \second\(), \first -.endm #if SANITIZER_ANDROID -WEAK_ALIAS ASM_WRAPPER_NAME(sigsetjmp), sigsetjmp -WEAK_ALIAS ASM_WRAPPER_NAME(setjmp_bionic), setjmp +ASM_TRAMPOLINE_ALIAS(sigsetjmp, sigsetjmp) +ASM_TRAMPOLINE_ALIAS(setjmp, setjmp_bionic) #else -WEAK_ALIAS ASM_WRAPPER_NAME(sigsetjmp), __sigsetjmp +ASM_TRAMPOLINE_ALIAS(__sigsetjmp, sigsetjmp) #endif -WEAK_ALIAS ASM_WRAPPER_NAME(setjmp), _setjmp +ASM_TRAMPOLINE_ALIAS(_setjmp, setjmp) #endif // We do not need executable stack. diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp_riscv64.S b/compiler-rt/lib/hwasan/hwasan_setjmp_riscv64.S --- a/compiler-rt/lib/hwasan/hwasan_setjmp_riscv64.S +++ b/compiler-rt/lib/hwasan/hwasan_setjmp_riscv64.S @@ -82,15 +82,10 @@ CFI_ENDPROC ASM_SIZE(ASM_WRAPPER_NAME(sigsetjmp)) - -.macro WEAK_ALIAS first second - .weak \second - .equ \second\(), \first -.endm - -WEAK_ALIAS ASM_WRAPPER_NAME(sigsetjmp), __sigsetjmp - -WEAK_ALIAS ASM_WRAPPER_NAME(setjmp), _setjmp +ASM_INTERCEPTOR_TRAMPOLINE(tail, sigsetjmp) +ASM_TRAMPOLINE_ALIAS(__sigsetjmp, sigsetjmp) +ASM_INTERCEPTOR_TRAMPOLINE(tail, setjmp) +ASM_TRAMPOLINE_ALIAS(_setjmp, setjmp) #endif // We do not need executable stack. diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S b/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S --- a/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S +++ b/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S @@ -69,14 +69,10 @@ CFI_ENDPROC ASM_SIZE(ASM_WRAPPER_NAME(sigsetjmp)) - -.macro WEAK_ALIAS first second - .weak \second - .equ \second\(), \first -.endm - -WEAK_ALIAS ASM_WRAPPER_NAME(sigsetjmp), __sigsetjmp -WEAK_ALIAS ASM_WRAPPER_NAME(setjmp), _setjmp +ASM_INTERCEPTOR_TRAMPOLINE(jmp, sigsetjmp) +ASM_TRAMPOLINE_ALIAS(__sigsetjmp, sigsetjmp) +ASM_INTERCEPTOR_TRAMPOLINE(jmp, setjmp) +ASM_TRAMPOLINE_ALIAS(_setjmp, setjmp) #endif // We do not need executable stack. diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -67,24 +67,50 @@ // 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 +// 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 resolve this we declare our interceptors with __interceptor_ -// prefix, and then make actual interceptors weak aliases to __interceptor_ -// functions. // -// 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. +// 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 by weak 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: +// +// - 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. +// // 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. @@ -118,35 +144,47 @@ } # define WRAP(x) wrap_##x +# define TRAMPOLINE(x) WRAP(x) # define WRAPPER_NAME(x) "wrap_"#x # define INTERCEPTOR_ATTRIBUTE # define DECLARE_WRAPPER(ret_type, func, ...) #elif SANITIZER_WINDOWS # define WRAP(x) __asan_wrap_##x +# define TRAMPOLINE(x) 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 SANITIZER_FREEBSD || SANITIZER_NETBSD +#elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS # define WRAP(x) __interceptor_ ## x +# define TRAMPOLINE(x) __interceptor_trampoline_ ## x # define WRAPPER_NAME(x) "__interceptor_" #x +# define TRAMPOLINE_NAME(x) "__interceptor_trampoline_" #x # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) +# 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 OVERRIDE_ATTRIBUTE +# else // SANITIZER_FREEBSD || SANITIZER_NETBSD +# define OVERRIDE_ATTRIBUTE __attribute__((weak)) +# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD +// 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, +// which calls the weak function _interceptor_func, which in turn calls the +// actual interceptor implementation __interceptor_func. To check if "func" was +// overridden by a foreign interceptor, we need another intermediate function +// __interceptor_trampoline_func. +# define DECLARE_WRAPPER(ret_type, func, ...) \ + extern "C" ret_type func(__VA_ARGS__) INTERCEPTOR_ATTRIBUTE \ + OVERRIDE_ATTRIBUTE __attribute__((alias(TRAMPOLINE_NAME(func)))); \ + extern "C" __attribute__((naked)) \ + ret_type TRAMPOLINE(func)(__VA_ARGS__) { ASM_JUMP(_interceptor_##func); } \ + extern "C" ret_type _interceptor_##func(__VA_ARGS__) INTERCEPTOR_ATTRIBUTE \ + __attribute__((weak, alias(WRAPPER_NAME(func)))); #endif #if SANITIZER_FUCHSIA @@ -176,14 +214,16 @@ #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, ...) diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h --- a/compiler-rt/lib/interception/interception_linux.h +++ b/compiler-rt/lib/interception/interception_linux.h @@ -23,9 +23,9 @@ 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) \ @@ -33,7 +33,7 @@ #func, \ (::__interception::uptr *) & REAL(func), \ (::__interception::uptr) & (func), \ - (::__interception::uptr) & WRAP(func)) + (::__interception::uptr) & TRAMPOLINE(func)) // dlvsym is a GNU extension supported by some other platforms. #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD @@ -42,7 +42,7 @@ #func, symver, \ (::__interception::uptr *) & REAL(func), \ (::__interception::uptr) & (func), \ - (::__interception::uptr) & WRAP(func)) + (::__interception::uptr) & TRAMPOLINE(func)) #else #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/compiler-rt/lib/interception/interception_linux.cpp b/compiler-rt/lib/interception/interception_linux.cpp --- a/compiler-rt/lib/interception/interception_linux.cpp +++ b/compiler-rt/lib/interception/interception_linux.cpp @@ -33,7 +33,7 @@ } #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 @@ // 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 @@ } 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/compiler-rt/lib/interception/tests/CMakeLists.txt b/compiler-rt/lib/interception/tests/CMakeLists.txt --- a/compiler-rt/lib/interception/tests/CMakeLists.txt +++ b/compiler-rt/lib/interception/tests/CMakeLists.txt @@ -4,6 +4,7 @@ set(INTERCEPTION_UNITTESTS interception_linux_test.cpp + interception_linux_foreign_test.cpp interception_test_main.cpp interception_win_test.cpp ) @@ -18,6 +19,9 @@ -I${COMPILER_RT_SOURCE_DIR}/lib -I${COMPILER_RT_SOURCE_DIR}/lib/interception -fno-rtti + -fno-builtin-isdigit + -fno-builtin-isalpha + -fno-builtin-isalnum -O2 -Werror=sign-compare) diff --git a/compiler-rt/lib/interception/tests/interception_linux_foreign_test.cpp b/compiler-rt/lib/interception/tests/interception_linux_foreign_test.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/interception/tests/interception_linux_foreign_test.cpp @@ -0,0 +1,65 @@ +//===-- interception_linux_foreign_test.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +// Tests that foreign interceptors work. +// +//===----------------------------------------------------------------------===// + +// Do not declare functions in ctype.h. +#define __NO_CTYPE + +#include "gtest/gtest.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +#if SANITIZER_LINUX + +extern "C" int _interceptor_isalpha(int d); + +extern "C" int isalnum(int d); +extern "C" int __interceptor_isalnum(int d); // the sanitizer interceptor + +static int isalpha_called; +static int isalnum_called; + +// Direct foreign interceptor. This is the "normal" protocol that other +// interceptors should follow. +extern "C" int isalpha(int d) { + ++isalpha_called; + return _interceptor_isalpha(d); +} + +// Indirect foreign interceptor. This pattern should only be used to co-exist +// with direct foreign interceptors and sanitizer interceptors. +extern "C" int _interceptor_isalnum(int d) { + ++isalnum_called; + return __interceptor_isalnum(d); +} + +namespace __interception { + +TEST(ForeignInterception, ForeignOverrideDirect) { + isalpha_called = 0; + EXPECT_NE(0, isalpha('a')); + EXPECT_EQ(1, isalpha_called); + EXPECT_EQ(0, isalpha('_')); + EXPECT_EQ(2, isalpha_called); +} + +TEST(ForeignInterception, ForeignOverrideIndirect) { + isalnum_called = 0; + EXPECT_NE(0, isalnum('a')); + EXPECT_EQ(1, isalnum_called); + EXPECT_EQ(0, isalnum('_')); + EXPECT_EQ(2, isalnum_called); +} + +} // namespace __interception + +#endif // SANITIZER_LINUX diff --git a/compiler-rt/lib/interception/tests/interception_linux_test.cpp b/compiler-rt/lib/interception/tests/interception_linux_test.cpp --- a/compiler-rt/lib/interception/tests/interception_linux_test.cpp +++ b/compiler-rt/lib/interception/tests/interception_linux_test.cpp @@ -11,36 +11,57 @@ // //===----------------------------------------------------------------------===// -// Do not declare isdigit in ctype.h. +// Do not declare functions in ctype.h. #define __NO_CTYPE #include "interception/interception.h" +#include + #include "gtest/gtest.h" -// Too slow for debug build -#if !SANITIZER_DEBUG #if SANITIZER_LINUX -static int InterceptorFunctionCalled; +static int isdigit_called; +static int isalpha_called; +static int isalnum_called; DECLARE_REAL(int, isdigit, int); +DECLARE_REAL(int, isalpha, int); +DECLARE_REAL(int, isalnum, int); + +INTERCEPTOR(void *, malloc, SIZE_T s) { return calloc(1, s); } +INTERCEPTOR(void, dummy_doesnt_exist__, ) { __builtin_trap(); } INTERCEPTOR(int, isdigit, int d) { - ++InterceptorFunctionCalled; + ++isdigit_called; return d >= '0' && d <= '9'; } +INTERCEPTOR(int, isalpha, int d) { + ++isalpha_called; + return (d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z'); +} + +INTERCEPTOR(int, isalnum, int d) { + ++isalnum_called; + return __interceptor_isalpha(d) || __interceptor_isdigit(d); +} + namespace __interception { TEST(Interception, InterceptFunction) { uptr malloc_address = 0; - EXPECT_TRUE(InterceptFunction("malloc", &malloc_address, 0, 0)); + EXPECT_TRUE(InterceptFunction("malloc", &malloc_address, (uptr)&malloc, + (uptr)&__interceptor_trampoline_malloc)); EXPECT_NE(0U, malloc_address); - EXPECT_FALSE(InterceptFunction("malloc", &malloc_address, 0, 1)); + EXPECT_FALSE(InterceptFunction("malloc", &malloc_address, (uptr)&calloc, + (uptr)&__interceptor_trampoline_malloc)); uptr dummy_address = 0; - EXPECT_FALSE(InterceptFunction("dummy_doesnt_exist__", &dummy_address, 0, 0)); + EXPECT_FALSE(InterceptFunction( + "dummy_doesnt_exist__", &dummy_address, (uptr)&dummy_doesnt_exist__, + (uptr)&__interceptor_trampoline_dummy_doesnt_exist__)); EXPECT_EQ(0U, dummy_address); } @@ -48,20 +69,51 @@ EXPECT_TRUE(INTERCEPT_FUNCTION(isdigit)); // After interception, the counter should be incremented. - InterceptorFunctionCalled = 0; + isdigit_called = 0; EXPECT_NE(0, isdigit('1')); - EXPECT_EQ(1, InterceptorFunctionCalled); + EXPECT_EQ(1, isdigit_called); EXPECT_EQ(0, isdigit('a')); - EXPECT_EQ(2, InterceptorFunctionCalled); + EXPECT_EQ(2, isdigit_called); // Calling the REAL function should not affect the counter. - InterceptorFunctionCalled = 0; + isdigit_called = 0; EXPECT_NE(0, REAL(isdigit)('1')); EXPECT_EQ(0, REAL(isdigit)('a')); - EXPECT_EQ(0, InterceptorFunctionCalled); + EXPECT_EQ(0, isdigit_called); +} + +TEST(Interception, ForeignOverrideDirect) { + // Actual interceptor is overridden. + EXPECT_FALSE(INTERCEPT_FUNCTION(isalpha)); + + isalpha_called = 0; + EXPECT_NE(0, isalpha('a')); + EXPECT_EQ(1, isalpha_called); + EXPECT_EQ(0, isalpha('_')); + EXPECT_EQ(2, isalpha_called); + + isalpha_called = 0; + EXPECT_NE(0, REAL(isalpha)('a')); + EXPECT_EQ(0, REAL(isalpha)('_')); + EXPECT_EQ(0, isalpha_called); +} + +TEST(Interception, ForeignOverrideIndirect) { + // Actual interceptor is _not_ overridden. + EXPECT_TRUE(INTERCEPT_FUNCTION(isalnum)); + + isalnum_called = 0; + EXPECT_NE(0, isalnum('a')); + EXPECT_EQ(1, isalnum_called); + EXPECT_EQ(0, isalnum('_')); + EXPECT_EQ(2, isalnum_called); + + isalnum_called = 0; + EXPECT_NE(0, REAL(isalnum)('a')); + EXPECT_EQ(0, REAL(isalnum)('_')); + EXPECT_EQ(0, isalnum_called); } } // namespace __interception #endif // SANITIZER_LINUX -#endif // #if !SANITIZER_DEBUG diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_asm.h b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_asm.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_asm.h @@ -49,6 +49,19 @@ # define ASM_SYMBOL(symbol) symbol # define ASM_SYMBOL_INTERCEPTOR(symbol) symbol # define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol +# define ASM_TRAMPOLINE_ALIAS(symbol, name) \ + .weak symbol; \ + .set symbol, __interceptor_trampoline_##name +# define ASM_INTERCEPTOR_TRAMPOLINE(jump, name) \ + .weak _interceptor_##name; \ + .set _interceptor_##name, ASM_WRAPPER_NAME(name); \ + .globl __interceptor_trampoline_##name; \ + ASM_TYPE_FUNCTION(__interceptor_trampoline_##name); \ + __interceptor_trampoline_##name: \ + CFI_STARTPROC; \ + jump _interceptor_##name; \ + CFI_ENDPROC; \ + ASM_SIZE(__interceptor_trampoline_##name) #else # define ASM_HIDDEN(symbol) # define ASM_TYPE_FUNCTION(symbol) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S @@ -40,8 +40,8 @@ ret ASM_SIZE(vfork) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(b, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) GNU_PROPERTY_BTI_PAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S @@ -43,7 +43,7 @@ ASM_SIZE(vfork) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(b, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S @@ -58,7 +58,7 @@ ret ASM_SIZE(vfork) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(jmp, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S @@ -51,7 +51,7 @@ jr $ra ASM_SIZE(vfork) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(b, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S @@ -50,7 +50,7 @@ ret ASM_SIZE(vfork) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(tail, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S @@ -34,9 +34,9 @@ .L_exit: pop %rax ret -ASM_SIZE(vfork) +ASM_SIZE(ASM_WRAPPER_NAME(vfork)) -.weak vfork -.set vfork, ASM_WRAPPER_NAME(vfork) +ASM_INTERCEPTOR_TRAMPOLINE(jmp, vfork) +ASM_TRAMPOLINE_ALIAS(vfork, vfork) #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -258,6 +258,20 @@ # define FALLTHROUGH #endif +// Plain jump to resume execution at the specified symbol. +#if SANITIZER_X64 || SANITIZER_X32 || SANITIZER_I386 || SANITIZER_SPARC +# define ASM_JUMP(sym) __asm__("jmp " SANITIZER_STRINGIFY(sym)) +#elif SANITIZER_ARM || SANITIZER_ARM64 || SANITIZER_MIPS || SANITIZER_PPC || \ + SANITIZER_LOONGARCH64 +# define ASM_JUMP(sym) __asm__("b " SANITIZER_STRINGIFY(sym)) +#elif SANITIZER_S390 +# define ASM_JUMP(sym) __asm__("jg " SANITIZER_STRINGIFY(sym)) +#elif SANITIZER_RISCV64 +# define ASM_JUMP(sym) __asm__("tail " SANITIZER_STRINGIFY(sym)) +#else +# error "ASM_JUMP: Unimplemented architecture" +#endif + // Unaligned versions of basic types. typedef ALIGNED(1) u16 uu16; typedef ALIGNED(1) u32 uu32;