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 @@ -14,6 +14,7 @@ #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_APPLE && \ @@ -67,24 +68,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 (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. +// // 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. @@ -131,20 +158,71 @@ # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); #elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS -# define WRAP(x) __interceptor_ ## x -# define TRAMPOLINE(x) WRAP(x) # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) -# if SANITIZER_FREEBSD || SANITIZER_NETBSD +# 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 OVERRIDE_ATTRIBUTE -# else // SANITIZER_FREEBSD || SANITIZER_NETBSD -# define OVERRIDE_ATTRIBUTE __attribute__((weak)) -# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD -# define DECLARE_WRAPPER(ret_type, func, ...) \ - extern "C" ret_type func(__VA_ARGS__) INTERCEPTOR_ATTRIBUTE \ - OVERRIDE_ATTRIBUTE ALIAS(WRAP(func)); +# define __ASM_WEAK_WRAPPER(func) +# 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 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 ) @@ -19,6 +20,10 @@ -I${COMPILER_RT_SOURCE_DIR}/lib/interception -DSANITIZER_COMMON_NO_REDEFINE_BUILTINS -fno-rtti + -fno-builtin-isdigit + -fno-builtin-isalpha + -fno-builtin-isalnum + -fno-builtin-islower -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,96 @@ +//===-- 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_asm.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +#if SANITIZER_LINUX + +extern "C" int isalnum(int d); +extern "C" int __interceptor_isalpha(int d); +extern "C" int ___interceptor_isalnum(int d); // the sanitizer interceptor +extern "C" int ___interceptor_islower(int d); // the sanitizer interceptor + +namespace __interception { +extern int isalpha_called; +extern int isalnum_called; +extern int islower_called; +} // namespace __interception +using namespace __interception; + +// Direct foreign interceptor. This is the "normal" protocol that other +// interceptors should follow. +extern "C" int isalpha(int d) { + // Use non-commutative arithmetic to verify order of calls. + isalpha_called = isalpha_called * 10 + 1; + return __interceptor_isalpha(d); +} + +#if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT +// 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 = isalnum_called * 10 + 1; + return ___interceptor_isalnum(d); +} + +extern "C" int __interceptor_islower(int d) { + islower_called = islower_called * 10 + 2; + return ___interceptor_islower(d); +} + +extern "C" int islower(int d) { + islower_called = islower_called * 10 + 1; + return __interceptor_islower(d); +} +#endif // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT + +namespace __interception { + +TEST(ForeignInterception, ForeignOverrideDirect) { + isalpha_called = 0; + EXPECT_NE(0, isalpha('a')); + EXPECT_EQ(13, isalpha_called); + isalpha_called = 0; + EXPECT_EQ(0, isalpha('_')); + EXPECT_EQ(13, isalpha_called); +} + +#if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT +TEST(ForeignInterception, ForeignOverrideIndirect) { + isalnum_called = 0; + EXPECT_NE(0, isalnum('a')); + EXPECT_EQ(13, isalnum_called); + isalnum_called = 0; + EXPECT_EQ(0, isalnum('_')); + EXPECT_EQ(13, isalnum_called); +} + +TEST(ForeignInterception, ForeignOverrideThree) { + islower_called = 0; + EXPECT_NE(0, islower('a')); + EXPECT_EQ(123, islower_called); + islower_called = 0; + EXPECT_EQ(0, islower('_')); + EXPECT_EQ(123, islower_called); +} +#endif // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT + +} // 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,68 @@ // //===----------------------------------------------------------------------===// -// 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; +namespace __interception { +int isalpha_called; +int isalnum_called; +int islower_called; +} // namespace __interception +using namespace __interception; DECLARE_REAL(int, isdigit, int); +DECLARE_REAL(int, isalpha, int); +DECLARE_REAL(int, isalnum, int); +DECLARE_REAL(int, islower, 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) { + // Use non-commutative arithmetic to verify order of calls. + isalpha_called = isalpha_called * 10 + 3; + return (d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z'); +} + +INTERCEPTOR(int, isalnum, int d) { + isalnum_called = isalnum_called * 10 + 3; + return __interceptor_isalpha(d) || __interceptor_isdigit(d); +} + +INTERCEPTOR(int, islower, int d) { + islower_called = islower_called * 10 + 3; + return d >= 'a' && d <= 'z'; +} + 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)&TRAMPOLINE(malloc))); EXPECT_NE(0U, malloc_address); - EXPECT_FALSE(InterceptFunction("malloc", &malloc_address, 0, 1)); + EXPECT_FALSE(InterceptFunction("malloc", &malloc_address, (uptr)&calloc, + (uptr)&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)&TRAMPOLINE(dummy_doesnt_exist__))); EXPECT_EQ(0U, dummy_address); } @@ -48,20 +80,72 @@ 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(13, isalpha_called); + isalpha_called = 0; + EXPECT_EQ(0, isalpha('_')); + EXPECT_EQ(13, isalpha_called); + + isalpha_called = 0; + EXPECT_NE(0, REAL(isalpha)('a')); + EXPECT_EQ(0, REAL(isalpha)('_')); + EXPECT_EQ(0, isalpha_called); +} + +#if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT +TEST(Interception, ForeignOverrideIndirect) { + // Actual interceptor is _not_ overridden. + EXPECT_TRUE(INTERCEPT_FUNCTION(isalnum)); + + isalnum_called = 0; + EXPECT_NE(0, isalnum('a')); + EXPECT_EQ(13, isalnum_called); + isalnum_called = 0; + EXPECT_EQ(0, isalnum('_')); + EXPECT_EQ(13, isalnum_called); + + isalnum_called = 0; + EXPECT_NE(0, REAL(isalnum)('a')); + EXPECT_EQ(0, REAL(isalnum)('_')); + EXPECT_EQ(0, isalnum_called); +} + +TEST(Interception, ForeignOverrideThree) { + // Actual interceptor is overridden. + EXPECT_FALSE(INTERCEPT_FUNCTION(islower)); + + islower_called = 0; + EXPECT_NE(0, islower('a')); + EXPECT_EQ(123, islower_called); + islower_called = 0; + EXPECT_EQ(0, islower('A')); + EXPECT_EQ(123, islower_called); + + islower_called = 0; + EXPECT_NE(0, REAL(islower)('a')); + EXPECT_EQ(0, REAL(islower)('A')); + EXPECT_EQ(0, islower_called); } +#endif // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT } // 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 @@ -42,17 +42,56 @@ # define CFI_RESTORE(reg) #endif +#if defined(__x86_64__) || defined(__i386__) || defined(__sparc__) +# define ASM_TAIL_CALL jmp +#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ + defined(__powerpc__) || defined(__loongarch_lp64) +# define ASM_TAIL_CALL b +#elif defined(__s390__) +# define ASM_TAIL_CALL jg +#elif defined(__riscv) +# define ASM_TAIL_CALL tail +#endif + +#if defined(__ELF__) && defined(__x86_64__) || defined(__i386__) || \ + defined(__riscv) +# define ASM_PREEMPTIBLE_SYM(sym) sym@plt +#else +# define ASM_PREEMPTIBLE_SYM(sym) sym +#endif + #if !defined(__APPLE__) # define ASM_HIDDEN(symbol) .hidden symbol # define ASM_TYPE_FUNCTION(symbol) .type symbol, %function # define ASM_SIZE(symbol) .size symbol, .-symbol # 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, ASM_WRAPPER_NAME(name) -# define ASM_INTERCEPTOR_TRAMPOLINE(name) +# if defined(__i386__) || defined(__powerpc__) +// For details, see interception.h +# define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol +# define ASM_TRAMPOLINE_ALIAS(symbol, name) \ + .weak symbol; \ + .set symbol, ASM_WRAPPER_NAME(name) +# define ASM_INTERCEPTOR_TRAMPOLINE(name) +# define ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT 0 +# else // Architecture supports interceptor trampoline +// Keep trampoline implementation in sync with interception/interception.h +# define ASM_WRAPPER_NAME(symbol) ___interceptor_##symbol +# define ASM_TRAMPOLINE_ALIAS(symbol, name) \ + .weak symbol; \ + .set symbol, __interceptor_trampoline_##name +# define ASM_INTERCEPTOR_TRAMPOLINE(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; \ + ASM_TAIL_CALL ASM_PREEMPTIBLE_SYM(__interceptor_##name); \ + CFI_ENDPROC; \ + ASM_SIZE(__interceptor_trampoline_##name) +# define ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT 1 +# endif // Architecture supports interceptor trampoline #else # define ASM_HIDDEN(symbol) # define ASM_TYPE_FUNCTION(symbol) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -5426,16 +5426,20 @@ extern "C" uptr __tls_get_offset(void *arg); extern "C" uptr TRAMPOLINE(__tls_get_offset)(void *arg); extern "C" uptr WRAP(__tls_get_offset)(void *arg); -// Now carefully intercept __tls_get_offset. +// Now carefully intercept __tls_get_offset. See DECLARE_WRAPPER for details. asm( ".text\n" -// The __intercept_ version has to exist, so that gen_dynamic_list.py -// exports our symbol. ".weak __tls_get_offset\n" - ".set __tls_get_offset, __interceptor___tls_get_offset\n" - ".global __interceptor___tls_get_offset\n" - ".type __interceptor___tls_get_offset, @function\n" - "__interceptor___tls_get_offset:\n" + ".set __tls_get_offset, __interceptor_trampoline___tls_get_offset\n" + ".global __interceptor_trampoline___tls_get_offset\n" + ".type __interceptor_trampoline___tls_get_offset, @function\n" + "__interceptor_trampoline___tls_get_offset:\n" + "jg __interceptor___tls_get_offset\n" + ".weak __interceptor___tls_get_offset\n" + ".set __interceptor___tls_get_offset, ___interceptor___tls_get_offset\n" + ".global ___interceptor___tls_get_offset\n" + ".type ___interceptor___tls_get_offset, @function\n" + "___interceptor___tls_get_offset:\n" #ifdef __s390x__ "la %r2, 0(%r2,%r12)\n" "jg __tls_get_addr_hidden\n" @@ -5446,7 +5450,7 @@ "b 0(%r4,%r3)\n" "1: .long __tls_get_addr_hidden - 0b\n" #endif - ".size __interceptor___tls_get_offset, .-__interceptor___tls_get_offset\n" + ".size ___interceptor___tls_get_offset, .-___interceptor___tls_get_offset\n" // Assembly wrapper to call REAL(__tls_get_offset)(arg) ".type __tls_get_offset_wrapper, @function\n" "__tls_get_offset_wrapper:\n" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -36,6 +36,8 @@ if (const char *s = try_strip("__asan_wrap_")) return s; } else { + if (const char *s = try_strip("___interceptor_")) + return s; if (const char *s = try_strip("__interceptor_")) return s; } diff --git a/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py b/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py --- a/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py +++ b/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py @@ -113,7 +113,7 @@ parser.add_argument("-o", "--output", required=True) args = parser.parse_args() - result = [] + result = set() all_functions = [] for library in args.libraries: @@ -122,36 +122,35 @@ for func in all_functions: # Export new/delete operators. if func in new_delete: - result.append(func) + result.add(func) continue # Export interceptors. - match = re.match("__interceptor_(.*)", func) + match = re.match("_?__interceptor_(.*)", func) if match: - result.append(func) + result.add(func) # We have to avoid exporting the interceptors for versioned library # functions due to gold internal error. orig_name = match.group(1) if orig_name in function_set and ( args.version_list or orig_name not in versioned_functions ): - result.append(orig_name) + result.add(orig_name) continue # Export sanitizer interface functions. if re.match("__sanitizer_(.*)", func): - result.append(func) + result.add(func) # Additional exported functions from files. for fname in args.extra: f = open(fname, "r") for line in f: - result.append(line.rstrip()) + result.add(line.rstrip()) # Print the resulting list in the format recognized by ld. with open(args.output, "w") as f: print("{", file=f) if args.version_list: print("global:", file=f) - result.sort() - for sym in result: + for sym in sorted(result): print(" %s;" % sym, file=f) if args.version_list: print("local:", file=f) diff --git a/compiler-rt/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cpp b/compiler-rt/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cpp --- a/compiler-rt/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cpp @@ -41,7 +41,7 @@ // CHECK: #0 {{.*}} in inc2 {{.*}}asan-symbolize-sanity-test.cpp:[[@LINE+21]] // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cpp:[[@LINE-4]] // CHECK: allocated by thread T{{.*}} here: - // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc + // CHECK: #{{.*}} in {{(wrap_|_?__interceptor_)?}}malloc // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cpp:[[@LINE-9]] return 0; }