diff options
| author | Michael Kruse <llvm-project@meinersbur.de> | 2025-01-03 10:22:51 +0100 |
|---|---|---|
| committer | Michael Kruse <llvm-project@meinersbur.de> | 2025-01-03 10:22:51 +0100 |
| commit | 38500d63e14ce340236840f60d356cdefb56a52c (patch) | |
| tree | 17edbec446ce9b50d2f215a483b83afb293a635d /compiler-rt | |
| parent | 1a3d5daaef7a6a63448a497da3eff7fc9e23df26 (diff) | |
| parent | 27f30029741ecf023baece7b3dde1ff9011ffefc (diff) | |
Merge branch 'main' into users/meinersbur/flang_runtime_split-headersusers/meinersbur/flang_runtime_split-headers
Diffstat (limited to 'compiler-rt')
152 files changed, 3882 insertions, 558 deletions
diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 80d5aaabfd8c..2c52788de56a 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -221,7 +221,7 @@ macro(handle_default_cxx_lib var) set(${var}_LIBNAME "${CMAKE_MATCH_1}") set(${var}_SYSTEM 1) elseif (${var} STREQUAL "default") - if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "OpenBSD") set(${var}_LIBNAME "libc++") set(${var}_SYSTEM 1) elseif (FUCHSIA) diff --git a/compiler-rt/Maintainers.md b/compiler-rt/Maintainers.md new file mode 100644 index 000000000000..5faf6741c467 --- /dev/null +++ b/compiler-rt/Maintainers.md @@ -0,0 +1,110 @@ +# Compiler-rt maintainers + +This file is a list of the +[maintainers](https://llvm.org/docs/DeveloperPolicy.html#maintainers) for +LLVM compiler-rt. + +## Current Maintainers + +The following people are the active maintainers for the project. Please reach +out to them for code reviews, questions about their area of expertise, or other +assistance. + +### Builtins Library + +Saleem Abdulrasool \ +compnerd@compnerd.org (email), [compnerd](https://github.com/compnerd) (GitHub) + +### CFI + +Peter Collingbourne \ +peter@pcc.me.uk (email), [pcc](https://github.com/pcc) (GitHub) + +### CMake build + +Petr Hosek \ +phosek@google.com (email), [petrhosek](https://github.com/petrhosek) (GitHub) + +### CRT + +Petr Hosek \ +phosek@google.com (email), [petrhosek](https://github.com/petrhosek) (GitHub) + +### GWP ASAN + +Christopher Ferris \ +cferris@google.com (email), [cferris1000](https://github.com/cferris1000) (GitHub) + +### MemProfiling + +Teresa Johnson \ +tejohnson@google.com (email), [teresajohnson](https://github.com/teresajohnson) (GitHub) + +### SafeStack + +Peter Collingbourne \ +peter@pcc.me.uk (email), [pcc](https://github.com/pcc) (GitHub) + +### Sanitizers + +#### Sanitizers not covered by someone else + +Vitaly Buka \ +vitalybuka@google.com (email), [vitalybuka](https://github.com/vitalybuka) (GitHub) \ +Alexander Potapenko \ +glider@google.com (email), [ramosian-glider](https://github.com/ramosian-glider) (GitHub) + +#### Data Flow Sanitizer + +Andrew Browne \ +browneee@google.com (email), [browneee](https://github.com/browneee) (GitHub) + +#### Numerical Sanitizer (NSAN) + +Alexander Shaposhnikov \ +alexander.v.shaposhnikov@gmail.com (email), [alexander-shaposhnikov](https://github.com/alexander-shaposhnikov) (GitHub) + +#### Realtime Sanitizer (RTSan) + +Christopher Apple \ +cja-private@pm.me (email), [cjappl](https://github.com/cjappl) (GitHub) \ +David Trevelyan \ +david.trevelyan@gmail.com (email), [davidtrevelyan](https://github.com/davidtrevelyan) (GitHub) + +#### Thread Sanitizer + +Dmitry Vyukov \ +dvyukov@google.com (email), [dvyukov](https://github.com/dvyukov) (GitHub) + +#### Undefined Behavior Sanitizer + +Richard Smith \ +richard-llvm@metafoo.co.uk (email), [zygoloid](https://github.com/zygoloid) (GitHub) + +### ORC + +Lang Hames \ +lhames@gmail.com (email), [lhames](https://github.com/lhames) (GitHub) + +### Profile runtime library + +Bill Wendling \ +isanbard@gmail.com (email), [isanbard](https://github.com/isanbard) (GitHub) + +### SCUDO + +Christopher Ferris \ +cferris@google.com (email), [cferris1000](https://github.com/cferris1000) (GitHub) + +## Inactive Maintainers + +The following people have graciously spent time performing maintainer +responsibilities but are no longer active in that role. Thank you for all your +help with the success of the project! + +### Inactive or former component maintainers + +Kostya Serebryany ([kcc](https://github.com/kcc)) -- Sanitizers \ +Evgeniy Stepanov ([eugenis](https://github.com/eugenis)) -- Sanitizers \ +Kostya Kortchinsky ([cryptoad](https://github.com/cryptoad)) -- SCUDO \ +Mitch Phillips ([hctim](https://github.com/hctim)) -- GWP ASAN diff --git a/compiler-rt/Maintainers.txt b/compiler-rt/Maintainers.txt deleted file mode 100644 index bd51a1073cc3..000000000000 --- a/compiler-rt/Maintainers.txt +++ /dev/null @@ -1,77 +0,0 @@ -This file is a list of the people responsible for ensuring that patches for a -particular part of compiler-rt are reviewed, either by themself or by -someone else. They are also the gatekeepers for their part of compiler-rt, with -the final word on what goes in or not. - -The list is sorted by surname and formatted to allow easy grepping and -beautification by scripts. The fields are: name (N), email (E), web-address -(W), PGP key ID and fingerprint (P), description (D), and snail-mail address -(S). - -N: Saleem Abdulrasool -E: compnerd@compnerd.org -D: builtins library - -N: Andrew Browne -E: browneee@google.com -D: DataFlowSanitizer - -N: Vitaly Buka -E: vitalybuka@google.com -D: Sanitizers - -N: Peter Collingbourne -E: peter@pcc.me.uk -D: CFI, SafeStack - -N: Lang Hames -E: lhames@gmail.com -D: ORC - -N: Petr Hosek -E: phosek@google.com -D: CRT, CMake build - -N: Teresa Johnson -E: tejohnson@google.com -D: MemProf - -N: Kostya Kortchinsky -E: kostya.kortchinsky@gmail.com -D: SCUDO - -N: Mitch Phillips -E: mitchp@google.com -D: GWP ASAN - -N: Alexander Potapenko -E: glider@google.com -D: Sanitizers - -N: Kostya Serebryany -E: kcc@google.com -D: AddressSanitizer, sanitizer_common, LeakSanitizer, LibFuzzer - -N: Richard Smith -E: richard-llvm@metafoo.co.uk -D: UndefinedBehaviorSanitizer - -N: Evgeniy Stepanov -E: eugenis@google.com -D: MemorySanitizer, Android port of sanitizers - -N: Dmitry Vyukov -E: dvyukov@google.com -D: ThreadSanitizer - -N: Bill Wendling -E: isanbard@gmail.com -D: Profile runtime library - -N: Christopher Apple, David Trevelyan -E: cja-private@pm.me, realtime.sanitizer@gmail.com -D: Realtime Sanitizer (RTSan) - -N: Alexander Shaposhnikov -E: alexander.v.shaposhnikov@gmail.com -D: Numerical Sanitizer (NSAN) diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index b29ae179c2b4..ab5d55a9a35c 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -85,6 +85,7 @@ else() set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} ${LOONGARCH64} ${RISCV64}) endif() +set(ALL_TYSAN_SUPPORTED_ARCH ${X86_64} ${ARM64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${LOONGARCH64}) @@ -102,7 +103,7 @@ if(APPLE) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM64}) else() set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} - powerpc64le ${HEXAGON} ${LOONGARCH64}) + powerpc64le ${HEXAGON} ${LOONGARCH64} ${RISCV32} ${RISCV64}) endif() set(ALL_XRAY_DSO_SUPPORTED_ARCH ${X86_64} ${ARM64}) set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64}) diff --git a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake index d8a491dbbd73..53aa750d934d 100644 --- a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake @@ -1,4 +1,3 @@ -include(CMakeParseArguments) include(CompilerRTUtils) function(get_aix_libatomic_default_link_flags link_flags export_list) diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake index 74a5d4edcd85..fa8c6be6c5d4 100644 --- a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -1,4 +1,3 @@ -include(CMakeParseArguments) include(CompilerRTUtils) include(BuiltinTests) diff --git a/compiler-rt/cmake/builtin-config-ix.cmake b/compiler-rt/cmake/builtin-config-ix.cmake index 1f63e158409c..706a1ff7eeb6 100644 --- a/compiler-rt/cmake/builtin-config-ix.cmake +++ b/compiler-rt/cmake/builtin-config-ix.cmake @@ -43,8 +43,9 @@ asm(\"cas w0, w1, [x2]\"); builtin_check_c_compiler_source(COMPILER_RT_HAS_AARCH64_SME " void foo(void) __arm_streaming_compatible { - asm(\".arch armv9-a+sme\"); + asm(\".arch armv9-a+sme2\"); asm(\"smstart\"); + asm(\"ldr zt0, [sp]\"); } ") diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 6d52eecc9a91..cf729c3adb1f 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -458,6 +458,7 @@ if(APPLE) set(SANITIZER_COMMON_SUPPORTED_OS osx) set(PROFILE_SUPPORTED_OS osx) set(TSAN_SUPPORTED_OS osx) + set(TYSAN_SUPPORTED_OS osx) set(XRAY_SUPPORTED_OS osx) set(FUZZER_SUPPORTED_OS osx) set(ORC_SUPPORTED_OS) @@ -593,6 +594,7 @@ if(APPLE) list(APPEND FUZZER_SUPPORTED_OS ${platform}) list(APPEND ORC_SUPPORTED_OS ${platform}) list(APPEND UBSAN_SUPPORTED_OS ${platform}) + list(APPEND TYSAN_SUPPORTED_OS ${platform}) list(APPEND LSAN_SUPPORTED_OS ${platform}) list(APPEND STATS_SUPPORTED_OS ${platform}) endif() @@ -651,6 +653,9 @@ if(APPLE) list_intersect(CTX_PROFILE_SUPPORTED_ARCH ALL_CTX_PROFILE_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(TYSAN_SUPPORTED_ARCH + ALL_TYSAN_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(TSAN_SUPPORTED_ARCH ALL_TSAN_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -703,6 +708,7 @@ else() filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH}) filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH ${ALL_CTX_PROFILE_SUPPORTED_ARCH}) filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH}) + filter_available_targets(TYSAN_SUPPORTED_ARCH ${ALL_TYSAN_SUPPORTED_ARCH}) filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH}) filter_available_targets(SAFESTACK_SUPPORTED_ARCH ${ALL_SAFESTACK_SUPPORTED_ARCH}) @@ -748,7 +754,7 @@ if(COMPILER_RT_SUPPORTED_ARCH) endif() message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}") -set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) +set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -843,6 +849,13 @@ else() set(COMPILER_RT_HAS_CTX_PROFILE FALSE) endif() +if (COMPILER_RT_HAS_SANITIZER_COMMON AND TYSAN_SUPPORTED_ARCH AND + OS_NAME MATCHES "Linux|Darwin") + set(COMPILER_RT_HAS_TYSAN TRUE) +else() + set(COMPILER_RT_HAS_TYSAN FALSE) +endif() + if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH) if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD") set(COMPILER_RT_HAS_TSAN TRUE) diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h index 4660a7818c92..6d9b2a2394f4 100644 --- a/compiler-rt/include/sanitizer/memprof_interface.h +++ b/compiler-rt/include/sanitizer/memprof_interface.h @@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void); /// User-provided default option settings. /// -/// You can provide your own implementation of this function to return a string -/// containing MemProf runtime options (for example, -/// <c>verbosity=1:print_stats=1</c>). +/// You can set these options via the -memprof-runtime-default-options LLVM flag +/// or you can provide your own implementation of this function. See +/// memprof_flags.h for more info. /// /// \returns Default options string. const char *SANITIZER_CDECL __memprof_default_options(void); diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 5ec995ae159b..e2f39f224df9 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -260,7 +260,6 @@ else() STATIC ARCHS ${ASAN_SUPPORTED_ARCH} OBJECT_LIBS RTAsan_cxx - RTUbsan_cxx CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS} PARENT_TARGET asan) diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index 56deb1b0d082..9cfb70bd00c7 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -240,6 +240,13 @@ void InitializeFlags() { DisplayHelpMessages(&asan_parser); ProcessFlags(); + + // TODO: Update other globals and data structures that may need to change + // after initialization due to new flags potentially being set changing after + // `__asan_default_options` is registered. + // See GH issue 'https://github.com/llvm/llvm-project/issues/117925' for + // details. + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); }); # if CAN_SANITIZE_UB diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 4129ee807612..e6c95dfb82c3 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -85,7 +85,7 @@ int OnExit() { // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ @@ -529,13 +529,13 @@ DEFINE_REAL(char*, index, const char *string, int c) return REAL(strcat)(to, from); } -INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { +INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncat); AsanInitFromRtl(); if (flags()->replace_str) { uptr from_length = MaybeRealStrnlen(from, size); - uptr copy_length = Min(size, from_length + 1); + uptr copy_length = Min<uptr>(size, from_length + 1); ASAN_READ_RANGE(ctx, from, copy_length); uptr to_length = internal_strlen(to); ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); @@ -617,12 +617,12 @@ INTERCEPTOR(char*, __strdup, const char *s) { } #endif // ASAN_INTERCEPT___STRDUP -INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { +INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncpy); AsanInitFromRtl(); if (flags()->replace_str) { - uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1); + uptr from_size = Min<uptr>(size, MaybeRealStrnlen(from, size) + 1); CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size); ASAN_READ_RANGE(ctx, from, from_size); ASAN_WRITE_RANGE(ctx, to, size); diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 826b45f5ada8..3e2386eaf809 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -124,11 +124,11 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_PTHREAD_ATFORK 0 #endif -DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) +DECLARE_REAL(int, memcmp, const void *a1, const void *a2, SIZE_T size) DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) -DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size) -DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen) +DECLARE_REAL(char*, strncpy, char *to, const char *from, SIZE_T size) +DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) DECLARE_REAL(char*, strstr, const char *s1, const char *s2) # if !SANITIZER_APPLE diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h index eb44f8f2f729..14727a5d665e 100644 --- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h +++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h @@ -18,8 +18,8 @@ #include "asan_mapping.h" #include "interception/interception.h" -DECLARE_REAL(void *, memcpy, void *to, const void *from, uptr size) -DECLARE_REAL(void *, memset, void *block, int c, uptr size) +DECLARE_REAL(void *, memcpy, void *to, const void *from, SIZE_T size) +DECLARE_REAL(void *, memset, void *block, int c, SIZE_T size) namespace __asan { diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt index 998e0ff24efa..00dcbf6534e2 100644 --- a/compiler-rt/lib/asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/asan/tests/CMakeLists.txt @@ -275,8 +275,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}> $<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}> $<TARGET_OBJECTS:RTLSanCommon.${arch}> - $<TARGET_OBJECTS:RTUbsan.${arch}> - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>) + $<TARGET_OBJECTS:RTUbsan.${arch}>) endif() add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS}) set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES @@ -303,7 +302,6 @@ if(ANDROID) $<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}> $<TARGET_OBJECTS:RTLSanCommon.${arch}> $<TARGET_OBJECTS:RTUbsan.${arch}> - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> ${COMPILER_RT_GTEST_SOURCE} ${ASAN_NOINST_TEST_SOURCES}) set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS}) diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 73c1b5062ec9..0581688c0546 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -310,6 +310,7 @@ set(x86_80_BIT_SOURCES mulxc3.c powixf2.c trunctfxf2.c + truncxfhf2.c ) if (NOT MSVC) @@ -572,9 +573,11 @@ set(aarch64_SOURCES aarch64/fp_mode.c ) +set(COMPILER_RT_AARCH64_FMV_USES_GLOBAL_CONSTRUCTOR NOT(FUCHSIA OR APPLE)) + if (COMPILER_RT_HAS_AARCH64_SME) - if (NOT COMPILER_RT_DISABLE_AARCH64_FMV AND COMPILER_RT_HAS_FNO_BUILTIN_FLAG AND (COMPILER_RT_HAS_AUXV OR COMPILER_RT_BAREMETAL_BUILD)) - list(APPEND aarch64_SOURCES aarch64/sme-abi.S aarch64/sme-libc-mem-routines.S aarch64/sme-abi-init.c aarch64/sme-abi-vg.c aarch64/sme-libc-routines.c) + if (NOT COMPILER_RT_DISABLE_AARCH64_FMV AND COMPILER_RT_HAS_FNO_BUILTIN_FLAG AND COMPILER_RT_AARCH64_FMV_USES_GLOBAL_CONSTRUCTOR) + list(APPEND aarch64_SOURCES aarch64/sme-abi.S aarch64/sme-libc-mem-routines.S aarch64/sme-abi-assert.c aarch64/sme-libc-routines.c) message(STATUS "AArch64 SME ABI routines enabled") set_source_files_properties(aarch64/sme-libc-routines.c PROPERTIES COMPILE_FLAGS "-fno-builtin") else() @@ -842,6 +845,8 @@ else () if(COMPILER_RT_DISABLE_AARCH64_FMV) list(APPEND BUILTIN_DEFS DISABLE_AARCH64_FMV) + elseif(COMPILER_RT_BAREMETAL_BUILD) + list(APPEND BUILTIN_DEFS ENABLE_BAREMETAL_AARCH64_FMV) endif() append_list_if(COMPILER_RT_HAS_ASM_LSE HAS_ASM_LSE BUILTIN_DEFS) diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c b/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c new file mode 100644 index 000000000000..37305ceb39c5 --- /dev/null +++ b/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c @@ -0,0 +1,11 @@ +// 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 + +// We rely on the FMV __aarch64_cpu_features mechanism to determine +// which features are set at runtime. + +#include "../cpu_model/AArch64CPUFeatures.inc" +_Static_assert(FEAT_SVE == 30, "sme-abi.S assumes FEAT_SVE = 30"); +_Static_assert(FEAT_SME == 42, "sme-abi.S assumes FEAT_SME = 42"); +_Static_assert(FEAT_SME2 == 57, "sme-abi.S assumes FEAT_SME2 = 57"); diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-init.c b/compiler-rt/lib/builtins/aarch64/sme-abi-init.c deleted file mode 100644 index d3cd8278a5d2..000000000000 --- a/compiler-rt/lib/builtins/aarch64/sme-abi-init.c +++ /dev/null @@ -1,50 +0,0 @@ -// 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 - -__attribute__((visibility("hidden"), nocommon)) -_Bool __aarch64_has_sme_and_tpidr2_el0; - -// We have multiple ways to check that the function has SME, depending on our -// target. -// * For Linux/Glibc we can use getauxval(). -// * For Android we can use getauxval(). -// * For newlib we can use __aarch64_sme_accessible(). - -#if defined(__linux__) - -#if defined(__ANDROID__) -#include <sys/auxv.h> -#elif __has_include(<sys/auxv.h>) -#include <sys/auxv.h> -#else -#define getauxval(x) 0 -#endif -#include "../cpu_model/aarch64/hwcap.inc" - -static _Bool has_sme(void) { return getauxval(AT_HWCAP2) & HWCAP2_SME; } - -#else // defined(__linux__) - -#if defined(COMPILER_RT_SHARED_LIB) -__attribute__((weak)) -#endif -extern _Bool __aarch64_sme_accessible(void); - -static _Bool has_sme(void) { -#if defined(COMPILER_RT_SHARED_LIB) - if (!__aarch64_sme_accessible) - return 0; -#endif - return __aarch64_sme_accessible(); -} - -#endif // defined(__linux__) - -#if __GNUC__ >= 9 -#pragma GCC diagnostic ignored "-Wprio-ctor-dtor" -#endif -__attribute__((constructor(90))) -static void init_aarch64_has_sme(void) { - __aarch64_has_sme_and_tpidr2_el0 = has_sme(); -} diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c b/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c deleted file mode 100644 index 4b9ee8c1d382..000000000000 --- a/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c +++ /dev/null @@ -1,18 +0,0 @@ -// 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 - -#include "../cpu_model/aarch64.h" - -struct FEATURES { - unsigned long long features; -}; - -extern struct FEATURES __aarch64_cpu_features; - -CONSTRUCTOR_ATTRIBUTE static void get_aarch64_cpu_features(void) { - if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) - return; - - __init_cpu_features(); -} diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi.S b/compiler-rt/lib/builtins/aarch64/sme-abi.S index 3e9bd2c23b2f..8dbbe061edb9 100644 --- a/compiler-rt/lib/builtins/aarch64/sme-abi.S +++ b/compiler-rt/lib/builtins/aarch64/sme-abi.S @@ -8,22 +8,23 @@ #include "../assembly.h" +.set FEAT_SVE_BIT, 30 +.set FEAT_SME_BIT, 42 +.set FEAT_SME2_BIT, 57 +.set FEAT_SME2_MASK, 1 << 57 +.set SVCR_PSTATE_SM_BIT, 0 #if !defined(__APPLE__) -#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) -#define TPIDR2_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) #define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features) #define CPU_FEATS_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_cpu_features) #else // MachO requires @page/@pageoff directives because the global is defined // in a different file. Otherwise this file may fail to build. -#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@page -#define TPIDR2_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@pageoff #define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features)@page #define CPU_FEATS_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_cpu_features)@pageoff #endif -.arch armv9-a+sme +.arch armv9-a+sme2 // Utility function which calls a system's abort() routine. Because the function // is streaming-compatible it should disable streaming-SVE mode before calling @@ -41,7 +42,7 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(do_abort) .cfi_offset w30, -24 .cfi_offset w29, -32 .cfi_offset 46, -16 - bl __arm_sme_state + bl SYMBOL_NAME(__arm_sme_state) tbz x0, #0, 2f 1: smstop sm @@ -55,15 +56,15 @@ END_COMPILERRT_FUNCTION(do_abort) // __arm_sme_state fills the result registers based on a local // that is set as part of the compiler-rt startup code. // __aarch64_has_sme_and_tpidr2_el0 -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) +DEFINE_COMPILERRT_FUNCTION(__arm_sme_state) .variant_pcs __arm_sme_state BTI_C mov x0, xzr mov x1, xzr - adrp x16, TPIDR2_SYMBOL - ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET] - cbz w16, 1f + adrp x16, CPU_FEATS_SYMBOL + ldr x16, [x16, CPU_FEATS_SYMBOL_OFFSET] + tbz x16, #FEAT_SME_BIT, 1f 0: orr x0, x0, #0xC000000000000000 mrs x16, SVCR @@ -71,9 +72,9 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) mrs x1, TPIDR2_EL0 1: ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sme_state) +END_COMPILERRT_FUNCTION(__arm_sme_state) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) +DEFINE_COMPILERRT_FUNCTION(__arm_tpidr2_restore) .variant_pcs __arm_tpidr2_restore BTI_C // If TPIDR2_EL0 is nonnull, the subroutine aborts in some platform-specific @@ -107,16 +108,16 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) ret 2: b SYMBOL_NAME(do_abort) -END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_restore) +END_COMPILERRT_FUNCTION(__arm_tpidr2_restore) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) +DEFINE_COMPILERRT_FUNCTION(__arm_tpidr2_save) .variant_pcs __arm_tpidr2_save BTI_C // If the current thread does not have access to TPIDR2_EL0, the subroutine // does nothing. - adrp x14, TPIDR2_SYMBOL - ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET] - cbz w14, 1f + adrp x14, CPU_FEATS_SYMBOL + ldr x14, [x14, CPU_FEATS_SYMBOL_OFFSET] + tbz x14, #FEAT_SME_BIT, 1f // If TPIDR2_EL0 is null, the subroutine does nothing. mrs x16, TPIDR2_EL0 @@ -148,16 +149,17 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) ret 2: b SYMBOL_NAME(do_abort) -END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_save) +END_COMPILERRT_FUNCTION(__arm_tpidr2_save) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) +DEFINE_COMPILERRT_FUNCTION(__arm_za_disable) + .cfi_startproc .variant_pcs __arm_za_disable BTI_C // If the current thread does not have access to SME, the subroutine does // nothing. - adrp x14, TPIDR2_SYMBOL - ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET] - cbz w14, 0f + adrp x14, CPU_FEATS_SYMBOL + ldr x14, [x14, CPU_FEATS_SYMBOL_OFFSET] + tbz x14, #FEAT_SME_BIT, 0f // Otherwise, the subroutine behaves as if it did the following: // * Call __arm_tpidr2_save. @@ -167,7 +169,7 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 - bl __arm_tpidr2_save + bl SYMBOL_NAME(__arm_tpidr2_save) // * Set TPIDR2_EL0 to null. msr TPIDR2_EL0, xzr @@ -182,47 +184,190 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) .cfi_restore w29 0: ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_za_disable) + .cfi_endproc +END_COMPILERRT_FUNCTION(__arm_za_disable) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_get_current_vg) +DEFINE_COMPILERRT_FUNCTION(__arm_get_current_vg) .variant_pcs __arm_get_current_vg BTI_C + adrp x17, CPU_FEATS_SYMBOL + ldr x17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbnz w17, #FEAT_SVE_BIT, 1f + tbz x17, #FEAT_SME_BIT, 2f +0: + mrs x17, SVCR + tbz x17, #SVCR_PSTATE_SM_BIT, 2f +1: + cntd x0 + ret +2: + mov x0, xzr + ret +END_COMPILERRT_FUNCTION(__arm_get_current_vg) + +// The diagram below describes the layout used in the following routines: +// * __arm_sme_state_size +// * __arm_sme_save +// * __arm_sme_restore +// +// +---------------------------------+ +// | ... | +// | ZA buffer | +// | ... | +// +---------------------------------+ <- @96 +// | ZT0 contents | +// +---------------------------------+ <- @32 +// | byte 15-10: zero (reserved) | +// | byte 9-8: num_za_save_slices | TPIDR2 block +// | byte 7-0: za_save_buffer | +// +---------------------------------+ <- @16 +// | bit 127-1: zero (reserved) | Internal state for __arm_sme_save/restore +// | bit 0: VALID | +// +---------------------------------+ <- @0 + +DEFINE_COMPILERRT_FUNCTION(__arm_sme_state_size) + .variant_pcs __arm_sme_state_size + BTI_C + + // Test if SME is available and ZA state is 'active'. + adrp x17, CPU_FEATS_SYMBOL + ldr x17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbz x17, #FEAT_SME_BIT, 0f + mrs x16, SVCR + tbz x16, #1, 0f + mrs x16, TPIDR2_EL0 + cbnz x16, 0f + + // Size = HAS_FEAT_SME2 ? 96 : 32 + tst x17, #FEAT_SME2_MASK + mov w17, #32 + mov w16, #96 + csel x16, x17, x16, eq + + // Size = Size + (SVLB * SVLB) + rdsvl x17, #1 + madd x0, x17, x17, x16 + ret + +0: + // Default case, 16 bytes is minimum (to encode VALID bit, multiple of 16 bytes) + mov w0, #16 + ret +END_COMPILERRT_FUNCTION(__arm_sme_state_size) + +DEFINE_COMPILERRT_FUNCTION(__arm_sme_save) + .variant_pcs __arm_sme_save + BTI_C + + // If PTR is not 16-byte aligned, abort. + tst x0, #0xF + b.ne 3f + + // Clear internal state bits + stp xzr, xzr, [x0] + + // If SME is not available, PSTATE.ZA = 0 or TPIDR2_EL0 != 0, return. + adrp x17, CPU_FEATS_SYMBOL + ldr x17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbz x17, #FEAT_SME_BIT, 2f + mrs x16, SVCR + tbz x16, #1, 2f + mrs x16, TPIDR2_EL0 + cbnz x16, 2f + + # ZA or ZT0 need saving, we can now set internal VALID bit to 1 + mov w16, #1 + str x16, [x0] + + add x18, x0, #32 + tbz x17, #FEAT_SME2_BIT, 1f + + // Store ZT0 + str zt0, [x18] + add x18, x18, #64 + +1: + // Set up lazy-save (x18 = pointer to buffer) + rdsvl x17, #1 + str x18, [x0, #16]! + strh w17, [x0, #8] + strh wzr, [x0, #10] + str wzr, [x0, #12] + msr TPIDR2_EL0, x0 + +2: + // Do nothing + ret + +3: + b SYMBOL_NAME(do_abort) +END_COMPILERRT_FUNCTION(__arm_sme_save) + +DEFINE_COMPILERRT_FUNCTION(__arm_sme_restore) + .cfi_startproc + .variant_pcs __arm_sme_restore + BTI_C + stp x29, x30, [sp, #-16]! .cfi_def_cfa_offset 16 mov x29, sp .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 + + // If PTR is not 16-byte aligned, abort. + tst x0, #0xF + b.ne 3f + + // If the VALID bit is 0, return early. + ldr x16, [x0] + cbz x16, 2f + + // If SME is not available, abort. adrp x17, CPU_FEATS_SYMBOL - ldr w17, [x17, CPU_FEATS_SYMBOL_OFFSET] - tbnz w17, #30, 0f - adrp x16, TPIDR2_SYMBOL - ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET] - cbz w16, 1f -0: - mov x18, x1 - bl __arm_sme_state - mov x1, x18 - and x17, x17, #0x40000000 - bfxil x17, x0, #0, #1 - cbz x17, 1f - cntd x0 - .cfi_def_cfa wsp, 16 - ldp x29, x30, [sp], #16 - .cfi_def_cfa_offset 0 - .cfi_restore w30 - .cfi_restore w29 - ret + ldr x17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbz x17, #FEAT_SME_BIT, 3f + + // If TPIDR2_EL0 != nullptr, no lazy-save was committed, try to reload zt0. + mrs x16, TPIDR2_EL0 + cbnz x16, 1f + + // If TPIDR2_EL0 == nullptr and PSTATE.ZA = 1 (<=> ZA state is 'active'), + // abort. + mrs x16, SVCR + tbnz x16, #1, 3f + + // Restore za. + smstart za + add x0, x0, #16 + bl __arm_tpidr2_restore + sub x0, x0, #16 + 1: - mov x0, xzr + smstart za + msr TPIDR2_EL0, xzr + + // Check if zt0 needs restoring. + tbz x17, #FEAT_SME2_BIT, 2f + + // Restore zt0. + add x16, x0, #32 + ldr zt0, [x16] + +2: + // Do nothing .cfi_def_cfa wsp, 16 ldp x29, x30, [sp], #16 .cfi_def_cfa_offset 0 .cfi_restore w30 .cfi_restore w29 ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_get_current_vg) + +3: + b SYMBOL_NAME(do_abort) + .cfi_endproc +END_COMPILERRT_FUNCTION(__arm_sme_restore) NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S b/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S index 6e13a03691cf..e736829967c0 100644 --- a/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S +++ b/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S @@ -6,8 +6,6 @@ #include "../assembly.h" -#define L(l) .L ## l - // // __arm_sc_memcpy / __arm_sc_memmove // @@ -52,17 +50,17 @@ The loop tail is handled by always copying 64 bytes from the end. */ -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memcpy) +DEFINE_COMPILERRT_FUNCTION(__arm_sc_memcpy) add srcend1, src, count add dstend1, dstin, count cmp count, 128 - b.hi L(copy_long) + b.hi 7f // copy_long cmp count, 32 - b.hi L(copy32_128) + b.hi 4f // copy32_128 /* Small copies: 0..32 bytes. */ cmp count, 16 - b.lo L(copy16) + b.lo 0f // copy16 ldp A_l, A_h, [src] ldp D_l, D_h, [srcend1, -16] stp A_l, A_h, [dstin] @@ -70,8 +68,8 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memcpy) ret /* Copy 8-15 bytes. */ -L(copy16): - tbz count, 3, L(copy8) +0: // copy16 + tbz count, 3, 1f // copy8 ldr A_l, [src] ldr A_h, [srcend1, -8] str A_l, [dstin] @@ -80,8 +78,8 @@ L(copy16): .p2align 3 /* Copy 4-7 bytes. */ -L(copy8): - tbz count, 2, L(copy4) +1: // copy8 + tbz count, 2, 2f // copy4 ldr A_lw, [src] ldr B_lw, [srcend1, -4] str A_lw, [dstin] @@ -89,8 +87,8 @@ L(copy8): ret /* Copy 0..3 bytes using a branchless sequence. */ -L(copy4): - cbz count, L(copy0) +2: // copy4 + cbz count, 3f // copy0 lsr tmp1, count, 1 ldrb A_lw, [src] ldrb C_lw, [srcend1, -1] @@ -98,18 +96,18 @@ L(copy4): strb A_lw, [dstin] strb B_lw, [dstin, tmp1] strb C_lw, [dstend1, -1] -L(copy0): +3: // copy0 ret .p2align 4 /* Medium copies: 33..128 bytes. */ -L(copy32_128): +4: // copy32_128 ldp A_l, A_h, [src] ldp B_l, B_h, [src, 16] ldp C_l, C_h, [srcend1, -32] ldp D_l, D_h, [srcend1, -16] cmp count, 64 - b.hi L(copy128) + b.hi 5f // copy128 stp A_l, A_h, [dstin] stp B_l, B_h, [dstin, 16] stp C_l, C_h, [dstend1, -32] @@ -118,16 +116,16 @@ L(copy32_128): .p2align 4 /* Copy 65..128 bytes. */ -L(copy128): +5: // copy128 ldp E_l, E_h, [src, 32] ldp F_l, F_h, [src, 48] cmp count, 96 - b.ls L(copy96) + b.ls 6f // copy96 ldp G_l, G_h, [srcend1, -64] ldp H_l, H_h, [srcend1, -48] stp G_l, G_h, [dstend1, -64] stp H_l, H_h, [dstend1, -48] -L(copy96): +6: // copy96 stp A_l, A_h, [dstin] stp B_l, B_h, [dstin, 16] stp E_l, E_h, [dstin, 32] @@ -138,12 +136,12 @@ L(copy96): .p2align 4 /* Copy more than 128 bytes. */ -L(copy_long): +7: // copy_long /* Use backwards copy if there is an overlap. */ sub tmp1, dstin, src - cbz tmp1, L(copy0) + cbz tmp1, 3b // copy0 cmp tmp1, count - b.lo L(copy_long_backwards) + b.lo 10f //copy_long_backwards /* Copy 16 bytes and then align dst to 16-byte alignment. */ @@ -158,8 +156,8 @@ L(copy_long): ldp C_l, C_h, [src, 48] ldp D_l, D_h, [src, 64]! subs count, count, 128 + 16 /* Test and readjust count. */ - b.ls L(copy64_from_end) -L(loop64): + b.ls 9f // copy64_from_end +8: // loop64 stp A_l, A_h, [dst, 16] ldp A_l, A_h, [src, 16] stp B_l, B_h, [dst, 32] @@ -169,10 +167,10 @@ L(loop64): stp D_l, D_h, [dst, 64]! ldp D_l, D_h, [src, 64]! subs count, count, 64 - b.hi L(loop64) + b.hi 8b // loop64 /* Write the last iteration and copy 64 bytes from the end. */ -L(copy64_from_end): +9: // copy64_from_end ldp E_l, E_h, [srcend1, -64] stp A_l, A_h, [dst, 16] ldp A_l, A_h, [srcend1, -48] @@ -191,7 +189,7 @@ L(copy64_from_end): /* Large backwards copy for overlapping copies. Copy 16 bytes and then align dst to 16-byte alignment. */ -L(copy_long_backwards): +10: // copy_long_backwards ldp D_l, D_h, [srcend1, -16] and tmp1, dstend1, 15 sub srcend1, srcend1, tmp1 @@ -203,9 +201,9 @@ L(copy_long_backwards): ldp D_l, D_h, [srcend1, -64]! sub dstend1, dstend1, tmp1 subs count, count, 128 - b.ls L(copy64_from_start) + b.ls 12f // copy64_from_start -L(loop64_backwards): +11: // loop64_backwards stp A_l, A_h, [dstend1, -16] ldp A_l, A_h, [srcend1, -16] stp B_l, B_h, [dstend1, -32] @@ -215,10 +213,10 @@ L(loop64_backwards): stp D_l, D_h, [dstend1, -64]! ldp D_l, D_h, [srcend1, -64]! subs count, count, 64 - b.hi L(loop64_backwards) + b.hi 11b // loop64_backwards /* Write the last iteration and copy 64 bytes from the start. */ -L(copy64_from_start): +12: // copy64_from_start ldp G_l, G_h, [src, 48] stp A_l, A_h, [dstend1, -16] ldp A_l, A_h, [src, 32] @@ -232,7 +230,7 @@ L(copy64_from_start): stp B_l, B_h, [dstin, 16] stp C_l, C_h, [dstin] ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memcpy) +END_COMPILERRT_FUNCTION(__arm_sc_memcpy) DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy) @@ -250,7 +248,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy) #define dstend2 x4 #define zva_val x5 -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) +DEFINE_COMPILERRT_FUNCTION(__arm_sc_memset) #ifdef __ARM_FEATURE_SVE mov z0.b, valw #else @@ -263,9 +261,9 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) add dstend2, dstin, count cmp count, 96 - b.hi L(set_long) + b.hi 7f // set_long cmp count, 16 - b.hs L(set_medium) + b.hs 4f // set_medium mov val, v0.D[0] /* Set 0..15 bytes. */ @@ -285,38 +283,38 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) 3: ret /* Set 17..96 bytes. */ -L(set_medium): +4: // set_medium str q0, [dstin] - tbnz count, 6, L(set96) + tbnz count, 6, 6f // set96 str q0, [dstend2, -16] - tbz count, 5, 1f + tbz count, 5, 5f str q0, [dstin, 16] str q0, [dstend2, -32] -1: ret +5: ret .p2align 4 /* Set 64..96 bytes. Write 64 bytes from the start and 32 bytes from the end. */ -L(set96): +6: // set96 str q0, [dstin, 16] stp q0, q0, [dstin, 32] stp q0, q0, [dstend2, -32] ret .p2align 4 -L(set_long): +7: // set_long and valw, valw, 255 bic dst, dstin, 15 str q0, [dstin] cmp count, 160 ccmp valw, 0, 0, hs - b.ne L(no_zva) + b.ne 9f // no_zva #ifndef SKIP_ZVA_CHECK mrs zva_val, dczid_el0 and zva_val, zva_val, 31 cmp zva_val, 4 /* ZVA size is 64 bytes. */ - b.ne L(no_zva) + b.ne 9f // no_zva #endif str q0, [dst, 16] stp q0, q0, [dst, 32] @@ -325,27 +323,27 @@ L(set_long): sub count, count, 128 /* Adjust count and bias for loop. */ .p2align 4 -L(zva_loop): +8: // zva_loop add dst, dst, 64 dc zva, dst subs count, count, 64 - b.hi L(zva_loop) + b.hi 8b // zva_loop stp q0, q0, [dstend2, -64] stp q0, q0, [dstend2, -32] ret -L(no_zva): +9: // no_zva sub count, dstend2, dst /* Count is 16 too large. */ sub dst, dst, 16 /* Dst is biased by -32. */ sub count, count, 64 + 16 /* Adjust count and bias for loop. */ -L(no_zva_loop): +10: // no_zva_loop stp q0, q0, [dst, 32] stp q0, q0, [dst, 64]! subs count, count, 64 - b.hi L(no_zva_loop) + b.hi 10b // no_zva_loop stp q0, q0, [dstend2, -64] stp q0, q0, [dstend2, -32] ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memset) +END_COMPILERRT_FUNCTION(__arm_sc_memset) #endif // __aarch64__ diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64.c b/compiler-rt/lib/builtins/cpu_model/aarch64.c index 74e5e01b66c5..4082fd62ea11 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64.c +++ b/compiler-rt/lib/builtins/cpu_model/aarch64.c @@ -80,6 +80,8 @@ struct { #include "aarch64/fmv/getauxval.inc" #elif defined(_WIN32) #include "aarch64/fmv/windows.inc" +#elif defined(ENABLE_BAREMETAL_AARCH64_FMV) +#include "aarch64/fmv/baremetal.inc" #else #include "aarch64/fmv/unimplemented.inc" #endif diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc new file mode 100644 index 000000000000..f188e84808e0 --- /dev/null +++ b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc @@ -0,0 +1,31 @@ +// For baremetal platforms, we don't really initialise '__aarch64_cpu_features', +// with exception of FEAT_SME that we can get from '__aarch64_sme_accessible'. + +#if defined(COMPILER_RT_SHARED_LIB) +__attribute__((weak)) +#endif +extern _Bool +__aarch64_sme_accessible(void); + +static _Bool has_sme(void) { +#if defined(COMPILER_RT_SHARED_LIB) + if (!__aarch64_sme_accessible) + return 0; +#endif + return __aarch64_sme_accessible(); +} + +void __init_cpu_features_resolver(unsigned long hwcap, + const __ifunc_arg_t *arg) {} + +void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) { + // CPU features already initialized. + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) + return; + + unsigned long long feat = 0; + if (has_sme()) + feat |= 1ULL << FEAT_SME; + + __atomic_store_n(&__aarch64_cpu_features.features, feat, __ATOMIC_RELAXED); +} diff --git a/compiler-rt/lib/builtins/fp_div_impl.inc b/compiler-rt/lib/builtins/fp_div_impl.inc index 29bcd1920edf..de61e55cd083 100644 --- a/compiler-rt/lib/builtins/fp_div_impl.inc +++ b/compiler-rt/lib/builtins/fp_div_impl.inc @@ -334,7 +334,6 @@ static __inline fp_t __divXf3__(fp_t a, fp_t b) { // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W x_UQ0 -= RECIPROCAL_PRECISION; // Now 1/b - (2*P) * 2^-W < x < 1/b - // FIXME Is x_UQ0 still >= 0.5? rep_t quotient_UQ1, dummy; wideMultiply(x_UQ0, aSignificand << 1, "ient_UQ1, &dummy); @@ -344,6 +343,12 @@ static __inline fp_t __divXf3__(fp_t a, fp_t b) { // adjust it to be in [1.0, 2.0) as UQ1.SB. rep_t residualLo; if (quotient_UQ1 < (implicitBit << 1)) { + if (quotient_UQ1 < implicitBit) { + // In a rare case where quotient is < 0.5, we can adjust the quotient and + // the written exponent, and then treat them the same way as in [0.5, 1.0) + quotient_UQ1 <<= 1; + writtenExponent -= 1; + } // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, // effectively doubling its value as well as its error estimation. residualLo = (aSignificand << (significandBits + 1)) - quotient_UQ1 * bSignificand; diff --git a/compiler-rt/lib/builtins/truncxfhf2.c b/compiler-rt/lib/builtins/truncxfhf2.c new file mode 100644 index 000000000000..0f0639865dbf --- /dev/null +++ b/compiler-rt/lib/builtins/truncxfhf2.c @@ -0,0 +1,15 @@ +//===-- lib/truncsfhf2.c - long double -> half conversion ---------*- C -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#define SRC_SINGLE +#define DST_HALF +#include "fp_trunc_impl.inc" + +COMPILER_RT_ABI dst_t __truncxfhf2(xf_float a) { + return __truncXfYf2__((float)a); +} diff --git a/compiler-rt/lib/hwasan/CMakeLists.txt b/compiler-rt/lib/hwasan/CMakeLists.txt index afafa0c4a927..207394130d03 100644 --- a/compiler-rt/lib/hwasan/CMakeLists.txt +++ b/compiler-rt/lib/hwasan/CMakeLists.txt @@ -188,7 +188,6 @@ function(add_hwasan_runtimes arch use_aliases) STATIC ARCHS ${arch} OBJECT_LIBS RTHwasan_cxx - RTUbsan_cxx CFLAGS ${hwasan_rtl_flags} PARENT_TARGET hwasan) diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h index 0580d97edda6..3cb6b446638e 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -37,7 +37,7 @@ #endif #define SIZE_T __sanitizer::usize -#define SSIZE_T __sanitizer::sptr +#define SSIZE_T __sanitizer::ssize typedef __sanitizer::sptr PTRDIFF_T; typedef __sanitizer::s64 INTMAX_T; typedef __sanitizer::u64 UINTMAX_T; diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index dc3018a675de..bd85c50a083a 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -213,6 +213,18 @@ static char* _strchr(char* str, char c) { return nullptr; } +static int _strcmp(const char *s1, const char *s2) { + while (true) { + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + } + return 0; +} + static void _memset(void *p, int value, size_t sz) { for (size_t i = 0; i < sz; ++i) ((char*)p)[i] = (char)value; @@ -418,7 +430,7 @@ static void *AllocateTrampolineRegion(uptr min_addr, uptr max_addr, ReportError( "interception_win: AllocateTrampolineRegion failed to find free memory; " "min_addr: %p, max_addr: %p, func_addr: %p, granularity: %zu\n", - (void *)min_addr, (void *)max_addr, granularity); + (void *)min_addr, (void *)max_addr, (void *)func_addr, granularity); return nullptr; #else return ::VirtualAlloc(nullptr, @@ -634,15 +646,17 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xD284: // 84 D2 : test dl,dl return 2; + case 0xE483: // 83 E4 XX : and esp, XX + case 0xEC83: // 83 EC XX : sub esp, XX + case 0xC1F6: // F6 C1 XX : test cl, XX + return 3; + // Cannot overwrite control-instruction. Return 0 to indicate failure. case 0x25FF: // FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX] return 0; } - switch (0x00FFFFFF & *(u32*)address) { - case 0xF8E483: // 83 E4 F8 : and esp, 0xFFFFFFF8 - case 0x64EC83: // 83 EC 64 : sub esp, 64h - return 3; + switch (0x00FFFFFF & *(u32 *)address) { case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX] return 7; } @@ -723,8 +737,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { return 7; } - switch (0x00FFFFFF & *(u32*)address) { - case 0x07c1f6: // f6 c1 07 : test cl, 0x7 + switch (0x00FFFFFF & *(u32 *)address) { case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax] case 0xc00b4d: // 4d 0b c0 : or r8, r8 case 0xc03345: // 45 33 c0 : xor r8d, r8d @@ -772,7 +785,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xdb8548: // 48 85 db : test rbx, rbx case 0xdb854d: // 4d 85 db : test r11, r11 case 0xdc8b4c: // 4c 8b dc : mov r11, rsp - case 0xe0e483: // 83 e4 e0 : and esp, 0xFFFFFFE0 case 0xe48548: // 48 85 e4 : test rsp, rsp case 0xe4854d: // 4d 85 e4 : test r12, r12 case 0xe58948: // 48 89 e5 : mov rbp, rsp @@ -808,7 +820,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x798141: // 41 81 79 XX YY YY YY YY : cmp DWORD PTR [r9+YY], XX XX XX XX case 0x7a8141: // 41 81 7a XX YY YY YY YY : cmp DWORD PTR [r10+YY], XX XX XX XX case 0x7b8141: // 41 81 7b XX YY YY YY YY : cmp DWORD PTR [r11+YY], XX XX XX XX - case 0x7c8141: // 41 81 7c XX YY YY YY YY : cmp DWORD PTR [r12+YY], XX XX XX XX case 0x7d8141: // 41 81 7d XX YY YY YY YY : cmp DWORD PTR [r13+YY], XX XX XX XX case 0x7e8141: // 41 81 7e XX YY YY YY YY : cmp DWORD PTR [r14+YY], XX XX XX XX case 0x7f8141: // 41 81 7f YY XX XX XX XX : cmp DWORD PTR [r15+YY], XX XX XX XX @@ -835,6 +846,10 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x2444c7: // C7 44 24 XX YY YY YY YY // mov dword ptr [rsp + XX], YYYYYYYY return 8; + + case 0x7c8141: // 41 81 7c ZZ YY XX XX XX XX + // cmp DWORD PTR [reg+reg*n+YY], XX XX XX XX + return 9; } switch (*(u32*)(address)) { @@ -868,7 +883,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x5D8B: // 8B 5D XX : mov ebx, dword ptr [ebp + XX] case 0x7D8B: // 8B 7D XX : mov edi, dword ptr [ebp + XX] case 0x758B: // 8B 75 XX : mov esi, dword ptr [ebp + XX] - case 0xEC83: // 83 EC XX : sub esp, XX case 0x75FF: // FF 75 XX : push dword ptr [ebp + XX] return 3; case 0xC1F7: // F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX @@ -1175,8 +1189,7 @@ static void **InterestingDLLsAvailable() { "libc++.dll", // libc++ "libunwind.dll", // libunwind # endif - // NTDLL should go last as it exports some functions that we should - // override in the CRT [presumably only used internally]. + // NTDLL must go last as it gets special treatment in OverrideFunction. "ntdll.dll", NULL }; @@ -1233,7 +1246,7 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { for (DWORD i = 0; i < exports->NumberOfNames; i++) { RVAPtr<char> name(module, names[i]); - if (!strcmp(func_name, name)) { + if (!_strcmp(func_name, name)) { DWORD index = ordinals[i]; RVAPtr<char> func(module, functions[index]); @@ -1247,7 +1260,7 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { char function_name[256]; size_t funtion_name_length = _strlen(func); if (funtion_name_length >= sizeof(function_name) - 1) { - ReportError("interception_win: func too long: '%s'\n", func); + ReportError("interception_win: func too long: '%s'\n", (char *)func); InterceptionFailed(); } @@ -1279,9 +1292,22 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { bool OverrideFunction( const char *func_name, uptr new_func, uptr *orig_old_func) { + static const char *kNtDllIgnore[] = { + "memcmp", "memcpy", "memmove", "memset" + }; + bool hooked = false; void **DLLs = InterestingDLLsAvailable(); for (size_t i = 0; DLLs[i]; ++i) { + if (DLLs[i + 1] == nullptr) { + // This is the last DLL, i.e. NTDLL. It exports some functions that + // we only want to override in the CRT. + for (const char *ignored : kNtDllIgnore) { + if (_strcmp(func_name, ignored) == 0) + return hooked; + } + } + uptr func_addr = InternalGetProcAddress(DLLs[i], func_name); if (func_addr && OverrideFunction(func_addr, new_func, orig_old_func)) { @@ -1335,7 +1361,7 @@ bool OverrideImportedFunction(const char *module_to_patch, RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name( module, name_table->u1.ForwarderString); const char *funcname = &import_by_name->Name[0]; - if (strcmp(funcname, function_name) == 0) + if (_strcmp(funcname, function_name) == 0) break; } } diff --git a/compiler-rt/lib/interception/tests/interception_win_test.cpp b/compiler-rt/lib/interception/tests/interception_win_test.cpp index 3c60d9c6f49d..04d9a6766f65 100644 --- a/compiler-rt/lib/interception/tests/interception_win_test.cpp +++ b/compiler-rt/lib/interception/tests/interception_win_test.cpp @@ -852,6 +852,8 @@ const struct InstructionSizeData { { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"}, { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"}, { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"}, + { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"}, + { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"}, { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"}, { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"}, { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"}, @@ -927,6 +929,7 @@ const struct InstructionSizeData { { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"}, { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"}, { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"}, + { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"}, { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"}, { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"}, { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"}, @@ -989,6 +992,7 @@ const struct InstructionSizeData { { 8, {0x41, 0x81, 0x7f, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7f YY XX XX XX XX : cmp DWORD PTR [r15+YY], XX XX XX XX"}, { 8, {0x81, 0x7c, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "81 7c 24 YY XX XX XX XX : cmp DWORD PTR [rsp+YY], XX XX XX XX"}, { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"}, + { 9, {0x41, 0x81, 0x7c, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "41 81 7c ZZ YY XX XX XX XX : cmp DWORD PTR [reg+reg*n+YY], XX XX XX XX"}, { 9, {0xA1, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "A1 XX XX XX XX XX XX XX XX : movabs eax, dword ptr ds:[XXXXXXXX]"}, #else // sorted list diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp index 19b2b9010682..c3448c22532b 100644 --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -301,7 +301,8 @@ struct Allocator { ~Allocator() { atomic_store_relaxed(&destructing, 1); - FinishAndWrite(); + if (flags()->dump_at_exit) + FinishAndWrite(); } static void PrintCallback(const uptr Key, LockedMemInfoBlock *const &Value, diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp index b107ff8fa0a7..95fde9d9672d 100644 --- a/compiler-rt/lib/memprof/memprof_flags.cpp +++ b/compiler-rt/lib/memprof/memprof_flags.cpp @@ -89,5 +89,5 @@ void InitializeFlags() { } // namespace __memprof SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) { - return ""; + return __memprof_default_options_str; } diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h index 2f2b628653dc..4dd395a6be94 100644 --- a/compiler-rt/lib/memprof/memprof_flags.h +++ b/compiler-rt/lib/memprof/memprof_flags.h @@ -17,13 +17,15 @@ #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_internal_defs.h" -// MemProf flag values can be defined in four ways: -// 1) initialized with default values at startup. -// 2) overriden during compilation of MemProf runtime by providing -// compile definition MEMPROF_DEFAULT_OPTIONS. -// 3) overriden from string returned by user-specified function -// __memprof_default_options(). -// 4) overriden from env variable MEMPROF_OPTIONS. +// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc. +// These values can be overridded in a number of ways, each option overrides the +// prior one: +// 1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf +// runtime +// 2) by setting the LLVM flag -memprof-runtime-default-options during the +// compilation of your binary +// 3) by overriding the user-specified function __memprof_default_options() +// 4) by setting the environment variable MEMPROF_OPTIONS during runtime namespace __memprof { diff --git a/compiler-rt/lib/memprof/memprof_flags.inc b/compiler-rt/lib/memprof/memprof_flags.inc index 7c5dc091f793..1d8e77752caa 100644 --- a/compiler-rt/lib/memprof/memprof_flags.inc +++ b/compiler-rt/lib/memprof/memprof_flags.inc @@ -38,4 +38,7 @@ MEMPROF_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, MEMPROF_FLAG(bool, print_text, false, "If set, prints the heap profile in text format. Else use the raw binary serialization format.") MEMPROF_FLAG(bool, print_terse, false, - "If set, prints memory profile in a terse format. Only applicable if print_text = true.")
\ No newline at end of file + "If set, prints memory profile in a terse format. Only applicable " + "if print_text = true.") +MEMPROF_FLAG(bool, dump_at_exit, true, + "If set, dump profiles when the program terminates.") diff --git a/compiler-rt/lib/memprof/memprof_interceptors.cpp b/compiler-rt/lib/memprof/memprof_interceptors.cpp index 53ee4e953419..f4d7fd46e619 100644 --- a/compiler-rt/lib/memprof/memprof_interceptors.cpp +++ b/compiler-rt/lib/memprof/memprof_interceptors.cpp @@ -49,7 +49,7 @@ int OnExit() { // ---------------------- Wrappers ---------------- {{{1 using namespace __memprof; -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ @@ -185,12 +185,12 @@ INTERCEPTOR(char *, strcat, char *to, const char *from) { return REAL(strcat)(to, from); } -INTERCEPTOR(char *, strncat, char *to, const char *from, uptr size) { +INTERCEPTOR(char *, strncat, char *to, const char *from, usize size) { void *ctx; MEMPROF_INTERCEPTOR_ENTER(ctx, strncat); ENSURE_MEMPROF_INITED(); uptr from_length = MaybeRealStrnlen(from, size); - uptr copy_length = Min(size, from_length + 1); + uptr copy_length = Min<uptr>(size, from_length + 1); MEMPROF_READ_RANGE(from, copy_length); uptr to_length = internal_strlen(to); MEMPROF_READ_STRING(to, to_length); @@ -239,11 +239,11 @@ INTERCEPTOR(char *, __strdup, const char *s) { return reinterpret_cast<char *>(new_mem); } -INTERCEPTOR(char *, strncpy, char *to, const char *from, uptr size) { +INTERCEPTOR(char *, strncpy, char *to, const char *from, usize size) { void *ctx; MEMPROF_INTERCEPTOR_ENTER(ctx, strncpy); ENSURE_MEMPROF_INITED(); - uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1); + uptr from_size = Min<uptr>(size, MaybeRealStrnlen(from, size) + 1); MEMPROF_READ_RANGE(from, from_size); MEMPROF_WRITE_RANGE(to, size); return REAL(strncpy)(to, from, size); diff --git a/compiler-rt/lib/memprof/memprof_interceptors.h b/compiler-rt/lib/memprof/memprof_interceptors.h index 20edef42a515..53d685706b84 100644 --- a/compiler-rt/lib/memprof/memprof_interceptors.h +++ b/compiler-rt/lib/memprof/memprof_interceptors.h @@ -33,11 +33,11 @@ void InitializePlatformInterceptors(); } // namespace __memprof -DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) +DECLARE_REAL(int, memcmp, const void *a1, const void *a2, SIZE_T size) DECLARE_REAL(char *, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) -DECLARE_REAL(char *, strncpy, char *to, const char *from, uptr size) -DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen) +DECLARE_REAL(char *, strncpy, char *to, const char *from, SIZE_T size) +DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) DECLARE_REAL(char *, strstr, const char *s1, const char *s2) #define MEMPROF_INTERCEPT_FUNC(name) \ diff --git a/compiler-rt/lib/memprof/memprof_interceptors_memintrinsics.h b/compiler-rt/lib/memprof/memprof_interceptors_memintrinsics.h index 0b87a6f3522a..99b6ccae126e 100644 --- a/compiler-rt/lib/memprof/memprof_interceptors_memintrinsics.h +++ b/compiler-rt/lib/memprof/memprof_interceptors_memintrinsics.h @@ -18,8 +18,8 @@ #include "memprof_internal.h" #include "memprof_mapping.h" -DECLARE_REAL(void *, memcpy, void *to, const void *from, uptr size) -DECLARE_REAL(void *, memset, void *block, int c, uptr size) +DECLARE_REAL(void *, memcpy, void *to, const void *from, SIZE_T size) +DECLARE_REAL(void *, memset, void *block, int c, SIZE_T size) namespace __memprof { diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h index 318bc4104405..7d3a937814a3 100644 --- a/compiler-rt/lib/memprof/memprof_interface_internal.h +++ b/compiler-rt/lib/memprof/memprof_interface_internal.h @@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats(); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char + __memprof_default_options_str[1]; + SANITIZER_INTERFACE_ATTRIBUTE const char *__memprof_default_options(); diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp index 2cc6c2df5a6f..ef8884a7e56f 100644 --- a/compiler-rt/lib/memprof/memprof_rtl.cpp +++ b/compiler-rt/lib/memprof/memprof_rtl.cpp @@ -27,6 +27,8 @@ #include <time.h> +SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1]; + uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol. // Allow the user to specify a profile output file via the binary. diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt index 271813612ab6..bfece89e2e15 100644 --- a/compiler-rt/lib/memprof/weak_symbols.txt +++ b/compiler-rt/lib/memprof/weak_symbols.txt @@ -1 +1 @@ -___memprof_default_options __memprof_profile_filename +___memprof_default_options_str ___memprof_default_options __memprof_profile_filename diff --git a/compiler-rt/lib/msan/CMakeLists.txt b/compiler-rt/lib/msan/CMakeLists.txt index b9976b258deb..a0b9c61584c9 100644 --- a/compiler-rt/lib/msan/CMakeLists.txt +++ b/compiler-rt/lib/msan/CMakeLists.txt @@ -66,7 +66,6 @@ foreach(arch ${MSAN_SUPPORTED_ARCH}) STATIC ARCHS ${arch} SOURCES ${MSAN_RTL_CXX_SOURCES} - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> ADDITIONAL_HEADERS ${MSAN_RTL_HEADERS} CFLAGS ${MSAN_RTL_CFLAGS} PARENT_TARGET msan) diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index f05c20618780..76255cdb742a 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -59,8 +59,8 @@ using __sanitizer::atomic_uintptr_t; DECLARE_REAL(SIZE_T, strlen, const char *s) DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) -DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) -DECLARE_REAL(void *, memset, void *dest, int c, uptr n) +DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n) +DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n) // True if this is a nested interceptor. static THREADLOCAL int in_interceptor_scope; diff --git a/compiler-rt/lib/msan/msan_poisoning.cpp b/compiler-rt/lib/msan/msan_poisoning.cpp index 1889e980bfc0..ac403681af40 100644 --- a/compiler-rt/lib/msan/msan_poisoning.cpp +++ b/compiler-rt/lib/msan/msan_poisoning.cpp @@ -17,9 +17,9 @@ #include "msan_thread.h" #include "sanitizer_common/sanitizer_common.h" -DECLARE_REAL(void *, memset, void *dest, int c, uptr n) -DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) -DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n) +DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n) +DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n) +DECLARE_REAL(void *, memmove, void *dest, const void *src, SIZE_T n) namespace __msan { diff --git a/compiler-rt/lib/nsan/nsan_allocator.cpp b/compiler-rt/lib/nsan/nsan_allocator.cpp index 19004ad7dc8d..128d37f52ba3 100644 --- a/compiler-rt/lib/nsan/nsan_allocator.cpp +++ b/compiler-rt/lib/nsan/nsan_allocator.cpp @@ -25,8 +25,8 @@ using namespace __nsan; -DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) -DECLARE_REAL(void *, memset, void *dest, int c, uptr n) +DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n) +DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n) namespace { struct Metadata { diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp index 5f25eba85607..2549f492b736 100644 --- a/compiler-rt/lib/nsan/nsan_interceptors.cpp +++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp @@ -28,7 +28,7 @@ using namespace __sanitizer; template <typename T> T min(T a, T b) { return a < b ? a : b; } -INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { +INTERCEPTOR(void *, memset, void *dst, int v, usize size) { // NOTE: This guard is needed because nsan's initialization code might call // memset. if (!nsan_initialized && REAL(memset) == nullptr) @@ -39,13 +39,13 @@ INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { return res; } -INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) { +INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, usize size) { wchar_t *res = REAL(wmemset)(dst, v, size); __nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size); return res; } -INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { +INTERCEPTOR(void *, memmove, void *dst, const void *src, usize size) { // NOTE: This guard is needed because nsan's initialization code might call // memmove. if (!nsan_initialized && REAL(memmove) == nullptr) @@ -57,13 +57,13 @@ INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { return res; } -INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, uptr size) { +INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, usize size) { wchar_t *res = REAL(wmemmove)(dst, src, size); __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); return res; } -INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { +INTERCEPTOR(void *, memcpy, void *dst, const void *src, usize size) { // NOTE: This guard is needed because nsan's initialization code might call // memcpy. if (!nsan_initialized && REAL(memcpy) == nullptr) { @@ -78,7 +78,7 @@ INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { return res; } -INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) { +INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, usize size) { wchar_t *res = REAL(wmemcpy)(dst, src, size); __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); return res; @@ -136,7 +136,7 @@ INTERCEPTOR(wchar_t *, wcsdup, const wchar_t *S) { return res; } -INTERCEPTOR(char *, strndup, const char *S, uptr size) { +INTERCEPTOR(char *, strndup, const char *S, usize size) { char *res = REAL(strndup)(S, size); if (res) { nsanCopyZeroTerminated(res, S, min(internal_strlen(S), size)); @@ -156,7 +156,7 @@ INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) { return res; } -INTERCEPTOR(char *, strncpy, char *dst, const char *src, uptr size) { +INTERCEPTOR(char *, strncpy, char *dst, const char *src, usize size) { char *res = REAL(strncpy)(dst, src, size); nsanCopyZeroTerminated(dst, src, min(size, internal_strlen(src))); return res; @@ -176,7 +176,7 @@ INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { return res; } -INTERCEPTOR(char *, strncat, char *dst, const char *src, uptr size) { +INTERCEPTOR(char *, strncat, char *dst, const char *src, usize size) { const auto DstLen = internal_strlen(dst); char *res = REAL(strncat)(dst, src, size); nsanCopyZeroTerminated(dst + DstLen, src, min(size, internal_strlen(src))); @@ -195,11 +195,10 @@ INTERCEPTOR(wchar_t *, wcpcpy, wchar_t *dst, const wchar_t *src) { return res; } -INTERCEPTOR(uptr, strxfrm, char *dst, const char *src, uptr size) { +INTERCEPTOR(usize, strxfrm, char *dst, const char *src, usize size) { // This is overly conservative, but this function should very rarely be used. __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst), internal_strlen(dst)); - const uptr res = REAL(strxfrm)(dst, src, size); - return res; + return REAL(strxfrm)(dst, src, size); } extern "C" int pthread_attr_init(void *attr); diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt index 36f4349a240e..7da230d8296e 100644 --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -3,10 +3,11 @@ # ORC runtime library common implementation files. set(ORC_COMMON_SOURCES debug.cpp + dlfcn_wrapper.cpp extensible_rtti.cpp log_error_to_stderr.cpp run_program_wrapper.cpp - dlfcn_wrapper.cpp + resolve.cpp ) # Common implementation headers will go here. @@ -51,6 +52,8 @@ if (APPLE) set(ORC_ASM_SOURCES macho_tlv.x86-64.S macho_tlv.arm64.S + sysv_reenter.arm64.S + sysv_reenter.x86-64.S ) set(ORC_IMPL_HEADERS @@ -116,6 +119,8 @@ else() # not Apple elfnix_tls.x86-64.S elfnix_tls.aarch64.S elfnix_tls.ppc64.S + sysv_reenter.arm64.S + sysv_reenter.x86-64.S ) endif() diff --git a/compiler-rt/lib/orc/macho_tlv.x86-64.S b/compiler-rt/lib/orc/macho_tlv.x86-64.S index e3daf23e3029..04b5bd7eba67 100644 --- a/compiler-rt/lib/orc/macho_tlv.x86-64.S +++ b/compiler-rt/lib/orc/macho_tlv.x86-64.S @@ -1,4 +1,4 @@ -//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===// +//===-- macho_tlv.x86-64.s --------------------------------------*- ASM -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/orc/resolve.cpp b/compiler-rt/lib/orc/resolve.cpp new file mode 100644 index 000000000000..3d9b37d14d2a --- /dev/null +++ b/compiler-rt/lib/orc/resolve.cpp @@ -0,0 +1,49 @@ +//===- resolve.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 contains a generic "resolver" function compatible with the +// __orc_rt_reenter function. +// +//===----------------------------------------------------------------------===// + +#include "executor_symbol_def.h" +#include "jit_dispatch.h" +#include "wrapper_function_utils.h" + +#include <stdio.h> + +#define DEBUG_TYPE "resolve" + +using namespace orc_rt; + +// Declare function tags for functions in the JIT process. +ORC_RT_JIT_DISPATCH_TAG(__orc_rt_resolve_tag) + +// FIXME: Make this configurable via an alias. +static void __orc_rt_resolve_fail(void *Caller, const char *ErrMsg) { + fprintf(stderr, "error resolving implementation for stub %p: %s\n", Caller, + ErrMsg); + abort(); +} + +extern "C" ORC_RT_HIDDEN void *__orc_rt_resolve(void *Caller) { + Expected<ExecutorSymbolDef> Result((ExecutorSymbolDef())); + if (auto Err = WrapperFunction<SPSExpected<SPSExecutorSymbolDef>( + SPSExecutorAddr)>::call(JITDispatch(&__orc_rt_resolve_tag), Result, + ExecutorAddr::fromPtr(Caller))) { + __orc_rt_resolve_fail(Caller, toString(std::move(Err)).c_str()); + return nullptr; // Unreachable. + } + + if (!Result) { + __orc_rt_resolve_fail(Caller, toString(Result.takeError()).c_str()); + return nullptr; // Unreachable. + } + + return Result->getAddress().toPtr<void *>(); +} diff --git a/compiler-rt/lib/orc/sysv_reenter.arm64.S b/compiler-rt/lib/orc/sysv_reenter.arm64.S new file mode 100644 index 000000000000..74941c459d6a --- /dev/null +++ b/compiler-rt/lib/orc/sysv_reenter.arm64.S @@ -0,0 +1,102 @@ +//===-- sysv_reenter.arm64.s ------------------------------------*- ASM -*-===// +// +// 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 the ORC runtime support library. +// +//===----------------------------------------------------------------------===// + +// The content of this file is arm64-only +#if defined(__arm64__) || defined(__aarch64__) + + .text + + // Saves GPRs, calls __orc_rt_resolve + .globl __orc_rt_sysv_reenter +__orc_rt_sysv_reenter: + // Save register state, set up new stack frome. + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + stp x14, x15, [sp, #-16]! + stp x12, x13, [sp, #-16]! + stp x10, x11, [sp, #-16]! + stp x8, x9, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x0, x1, [sp, #-16]! + stp q30, q31, [sp, #-32]! + stp q28, q29, [sp, #-32]! + stp q26, q27, [sp, #-32]! + stp q24, q25, [sp, #-32]! + stp q22, q23, [sp, #-32]! + stp q20, q21, [sp, #-32]! + stp q18, q19, [sp, #-32]! + stp q16, q17, [sp, #-32]! + stp q14, q15, [sp, #-32]! + stp q12, q13, [sp, #-32]! + stp q10, q11, [sp, #-32]! + stp q8, q9, [sp, #-32]! + stp q6, q7, [sp, #-32]! + stp q4, q5, [sp, #-32]! + stp q2, q3, [sp, #-32]! + stp q0, q1, [sp, #-32]! + + // Look up the return address and subtract 8 from it (on the assumption + // that it's a standard arm64 reentry trampoline) to get back the + // trampoline's address. + sub x0, x30, #8 + + // Call __orc_rt_resolve to look up the implementation corresponding to + // the calling stub, then store this in x17 (which we'll return to + // below). +#if !defined(__APPLE__) + bl __orc_rt_resolve +#else + bl ___orc_rt_resolve +#endif + mov x17, x0 + + // Restore the register state. + ldp q0, q1, [sp], #32 + ldp q2, q3, [sp], #32 + ldp q4, q5, [sp], #32 + ldp q6, q7, [sp], #32 + ldp q8, q9, [sp], #32 + ldp q10, q11, [sp], #32 + ldp q12, q13, [sp], #32 + ldp q14, q15, [sp], #32 + ldp q16, q17, [sp], #32 + ldp q18, q19, [sp], #32 + ldp q20, q21, [sp], #32 + ldp q22, q23, [sp], #32 + ldp q24, q25, [sp], #32 + ldp q26, q27, [sp], #32 + ldp q28, q29, [sp], #32 + ldp q30, q31, [sp], #32 + ldp x0, x1, [sp], #16 + ldp x2, x3, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x8, x9, [sp], #16 + ldp x10, x11, [sp], #16 + ldp x12, x13, [sp], #16 + ldp x14, x15, [sp], #16 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x29, x30, [sp], #16 + + // Return to the function implementation (rather than the stub). + ret x17 + +#endif // defined(__arm64__) || defined(__aarch64__) diff --git a/compiler-rt/lib/orc/sysv_reenter.x86-64.S b/compiler-rt/lib/orc/sysv_reenter.x86-64.S new file mode 100644 index 000000000000..0a36280f1d1f --- /dev/null +++ b/compiler-rt/lib/orc/sysv_reenter.x86-64.S @@ -0,0 +1,81 @@ +//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===// +// +// 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 the ORC runtime support library. +// +//===----------------------------------------------------------------------===// + +// The content of this file is x86_64-only +#if defined(__x86_64__) + +// Save all GRPS except %rsp. +// This value is also subtracted from %rsp below, despite the fact that %rbp +// has already been pushed, because we need %rsp to stay 16-byte aligned. +#define GPR_SAVE_SPACE_SIZE 15 * 8 +#define FXSAVE64_SAVE_SPACE_SIZE 512 +#define REGISTER_SAVE_SPACE_SIZE \ + GPR_SAVE_SPACE_SIZE + FXSAVE64_SAVE_SPACE_SIZE + + .text + + // returns address of TLV in %rax, all other registers preserved + .globl __orc_rt_sysv_reenter +__orc_rt_sysv_reenter: + pushq %rbp + movq %rsp, %rbp + subq $REGISTER_SAVE_SPACE_SIZE, %rsp + movq %rax, -8(%rbp) + movq %rbx, -16(%rbp) + movq %rcx, -24(%rbp) + movq %rdx, -32(%rbp) + movq %rsi, -40(%rbp) + movq %rdi, -48(%rbp) + movq %r8, -56(%rbp) + movq %r9, -64(%rbp) + movq %r10, -72(%rbp) + movq %r11, -80(%rbp) + movq %r12, -88(%rbp) + movq %r13, -96(%rbp) + movq %r14, -104(%rbp) + movq %r15, -112(%rbp) + fxsave64 (%rsp) + movq 8(%rbp), %rdi + + // Load return address and subtract five from it (on the assumption + // that it's a call instruction). + subq $5, %rdi + + // Call __orc_rt_resolve to look up the implementation corresponding to + // the calling stub, then store this in x17 (which we'll return to + // below). +#if !defined(__APPLE__) + call __orc_rt_resolve +#else + call ___orc_rt_resolve +#endif + movq %rax, 8(%rbp) + fxrstor64 (%rsp) + movq -112(%rbp), %r15 + movq -104(%rbp), %r14 + movq -96(%rbp), %r13 + movq -88(%rbp), %r12 + movq -80(%rbp), %r11 + movq -72(%rbp), %r10 + movq -64(%rbp), %r9 + movq -56(%rbp), %r8 + movq -48(%rbp), %rdi + movq -40(%rbp), %rsi + movq -32(%rbp), %rdx + movq -24(%rbp), %rcx + movq -16(%rbp), %rbx + movq -8(%rbp), %rax + addq $REGISTER_SAVE_SPACE_SIZE, %rsp + popq %rbp + ret + +#endif // defined(__x86_64__) diff --git a/compiler-rt/lib/orc/tests/unit/CMakeLists.txt b/compiler-rt/lib/orc/tests/unit/CMakeLists.txt index aec689a407be..16cd16c45683 100644 --- a/compiler-rt/lib/orc/tests/unit/CMakeLists.txt +++ b/compiler-rt/lib/orc/tests/unit/CMakeLists.txt @@ -2,6 +2,7 @@ set(UNITTEST_SOURCES adt_test.cpp bitmask_enum_test.cpp c_api_test.cpp + common.cpp endian_test.cpp error_test.cpp executor_address_test.cpp diff --git a/compiler-rt/lib/orc/tests/unit/common.cpp b/compiler-rt/lib/orc/tests/unit/common.cpp new file mode 100644 index 000000000000..9479cc809430 --- /dev/null +++ b/compiler-rt/lib/orc/tests/unit/common.cpp @@ -0,0 +1,6 @@ +#include <stdio.h> + +/// Defined so that tests can use code that logs errors. +extern "C" void __orc_rt_log_error(const char *ErrMsg) { + fprintf(stderr, "orc runtime error: %s\n", ErrMsg); +} diff --git a/compiler-rt/lib/profile/InstrProfilingMerge.c b/compiler-rt/lib/profile/InstrProfilingMerge.c index 7cf1679811eb..92721c4fd55e 100644 --- a/compiler-rt/lib/profile/InstrProfilingMerge.c +++ b/compiler-rt/lib/profile/InstrProfilingMerge.c @@ -137,27 +137,23 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, return 1; } - __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; - char *SrcCountersStart, *DstCounter; - const char *SrcCountersEnd, *SrcCounter; - const char *SrcBitmapStart; - const char *SrcNameStart; - const char *SrcValueProfDataStart, *SrcValueProfData; uintptr_t CountersDelta = Header->CountersDelta; uintptr_t BitmapDelta = Header->BitmapDelta; - SrcDataStart = + __llvm_profile_data *SrcDataStart = (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) + Header->BinaryIdsSize); - SrcDataEnd = SrcDataStart + Header->NumData; - SrcCountersStart = (char *)SrcDataEnd; - SrcCountersEnd = SrcCountersStart + - Header->NumCounters * __llvm_profile_counter_entry_size(); - SrcBitmapStart = SrcCountersEnd + __llvm_profile_get_num_padding_bytes( - SrcCountersEnd - SrcCountersStart); - SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes; - SrcValueProfDataStart = + __llvm_profile_data *SrcDataEnd = SrcDataStart + Header->NumData; + uintptr_t SrcCountersStart = (uintptr_t)SrcDataEnd; + uintptr_t SrcCountersEnd = + SrcCountersStart + + Header->NumCounters * __llvm_profile_counter_entry_size(); + uintptr_t SrcBitmapStart = + SrcCountersEnd + + __llvm_profile_get_num_padding_bytes(SrcCountersEnd - SrcCountersStart); + uintptr_t SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes; + uintptr_t SrcValueProfDataStart = SrcNameStart + getDistanceFromCounterToValueProf(Header); if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart) return 1; @@ -165,13 +161,13 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, // Merge counters by iterating the entire counter section when data section is // empty due to correlation. if (Header->NumData == 0) { - for (SrcCounter = SrcCountersStart, - DstCounter = __llvm_profile_begin_counters(); + for (uintptr_t SrcCounter = SrcCountersStart, + DstCounter = (uintptr_t)__llvm_profile_begin_counters(); SrcCounter < SrcCountersEnd;) { if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) { - *DstCounter &= *SrcCounter; + *(char *)DstCounter &= *(const char *)SrcCounter; } else { - *(uint64_t *)DstCounter += *(uint64_t *)SrcCounter; + *(uint64_t *)DstCounter += *(const uint64_t *)SrcCounter; } SrcCounter += __llvm_profile_counter_entry_size(); DstCounter += __llvm_profile_counter_entry_size(); @@ -179,6 +175,8 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, return 0; } + __llvm_profile_data *SrcData, *DstData; + uintptr_t SrcValueProfData; for (SrcData = SrcDataStart, DstData = (__llvm_profile_data *)__llvm_profile_begin_data(), SrcValueProfData = SrcValueProfDataStart; @@ -187,10 +185,10 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, // address of the data to the start address of the counter. On WIN64, // CounterPtr is a truncated 32-bit value due to COFF limitation. Sign // extend CounterPtr to get the original value. - char *DstCounters = - (char *)((uintptr_t)DstData + signextIfWin64(DstData->CounterPtr)); - char *DstBitmap = - (char *)((uintptr_t)DstData + signextIfWin64(DstData->BitmapPtr)); + uintptr_t DstCounters = + (uintptr_t)DstData + signextIfWin64(DstData->CounterPtr); + uintptr_t DstBitmap = + (uintptr_t)DstData + signextIfWin64(DstData->BitmapPtr); unsigned NVK = 0; // SrcData is a serialized representation of the memory image. We need to @@ -200,7 +198,7 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, // CountersDelta computes the offset into the in-buffer counter section. // // On WIN64, CountersDelta is truncated as well, so no need for signext. - char *SrcCounters = + uintptr_t SrcCounters = SrcCountersStart + ((uintptr_t)SrcData->CounterPtr - CountersDelta); // CountersDelta needs to be decreased as we advance to the next data // record. @@ -214,13 +212,13 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, for (unsigned I = 0; I < NC; I++) { if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) { // A value of zero signifies the function is covered. - DstCounters[I] &= SrcCounters[I]; + ((char *)DstCounters)[I] &= ((const char *)SrcCounters)[I]; } else { - ((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I]; + ((uint64_t *)DstCounters)[I] += ((const uint64_t *)SrcCounters)[I]; } } - const char *SrcBitmap = + uintptr_t SrcBitmap = SrcBitmapStart + ((uintptr_t)SrcData->BitmapPtr - BitmapDelta); // BitmapDelta also needs to be decreased as we advance to the next data // record. @@ -232,7 +230,7 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, return 1; // Merge Src and Dst Bitmap bytes by simply ORing them together. for (unsigned I = 0; I < NB; I++) - DstBitmap[I] |= SrcBitmap[I]; + ((char *)DstBitmap)[I] |= ((const char *)SrcBitmap)[I]; } /* Now merge value profile data. */ @@ -245,7 +243,7 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData, if (!NVK) continue; - if (SrcValueProfData >= ProfileData + ProfileSize) + if (SrcValueProfData >= (uintptr_t)ProfileData + ProfileSize) return 1; VPMergeHook((ValueProfData *)SrcValueProfData, DstData); SrcValueProfData = diff --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp index 81cedb3b5114..73340b34f6d4 100644 --- a/compiler-rt/lib/rtsan/rtsan.cpp +++ b/compiler-rt/lib/rtsan/rtsan.cpp @@ -83,6 +83,9 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() { SanitizerToolName = "RealtimeSanitizer"; InitializeFlags(); + + InitializePlatformEarly(); + InitializeInterceptors(); InitializeSuppressions(); diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp index 4f7b534ee17a..4e51f464b573 100644 --- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp @@ -46,6 +46,7 @@ void OSSpinLockLock(volatile OSSpinLock *__lock); #include <pthread.h> #include <stdarg.h> #include <stdio.h> +#include <sys/select.h> #include <sys/socket.h> #include <sys/stat.h> #include <time.h> @@ -244,14 +245,29 @@ INTERCEPTOR(FILE *, fopen, const char *path, const char *mode) { return REAL(fopen)(path, mode); } +INTERCEPTOR(FILE *, freopen, const char *path, const char *mode, FILE *stream) { + __rtsan_notify_intercepted_call("freopen"); + return REAL(freopen)(path, mode, stream); +} + +// Streams + #if SANITIZER_INTERCEPT_FOPEN64 INTERCEPTOR(FILE *, fopen64, const char *path, const char *mode) { __rtsan_notify_intercepted_call("fopen64"); return REAL(fopen64)(path, mode); } -#define RTSAN_MAYBE_INTERCEPT_FOPEN64 INTERCEPT_FUNCTION(fopen64) + +INTERCEPTOR(FILE *, freopen64, const char *path, const char *mode, + FILE *stream) { + __rtsan_notify_intercepted_call("freopen64"); + return REAL(freopen64)(path, mode, stream); +} +#define RTSAN_MAYBE_INTERCEPT_FOPEN64 INTERCEPT_FUNCTION(fopen64); +#define RTSAN_MAYBE_INTERCEPT_FREOPEN64 INTERCEPT_FUNCTION(freopen64); #else #define RTSAN_MAYBE_INTERCEPT_FOPEN64 +#define RTSAN_MAYBE_INTERCEPT_FREOPEN64 #endif // SANITIZER_INTERCEPT_FOPEN64 INTERCEPTOR(size_t, fread, void *ptr, size_t size, size_t nitems, @@ -276,7 +292,28 @@ INTERCEPTOR(int, fputs, const char *s, FILE *stream) { return REAL(fputs)(s, stream); } -// Streams +INTERCEPTOR(FILE *, fdopen, int fd, const char *mode) { + __rtsan_notify_intercepted_call("fdopen"); + return REAL(fdopen)(fd, mode); +} + +#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM +INTERCEPTOR(FILE *, open_memstream, char **buf, size_t *size) { + __rtsan_notify_intercepted_call("open_memstream"); + return REAL(open_memstream)(buf, size); +} + +INTERCEPTOR(FILE *, fmemopen, void *buf, size_t size, const char *mode) { + __rtsan_notify_intercepted_call("fmemopen"); + return REAL(fmemopen)(buf, size, mode); +} +#define RTSAN_MAYBE_INTERCEPT_OPEN_MEMSTREAM INTERCEPT_FUNCTION(open_memstream) +#define RTSAN_MAYBE_INTERCEPT_FMEMOPEN INTERCEPT_FUNCTION(fmemopen) +#else +#define RTSAN_MAYBE_INTERCEPT_OPEN_MEMSTREAM +#define RTSAN_MAYBE_INTERCEPT_FMEMOPEN +#endif + INTERCEPTOR(int, puts, const char *s) { __rtsan_notify_intercepted_call("puts"); return REAL(puts)(s); @@ -707,6 +744,17 @@ INTERCEPTOR(int, shutdown, int socket, int how) { return REAL(shutdown)(socket, how); } +#if SANITIZER_INTERCEPT_ACCEPT4 +INTERCEPTOR(int, accept4, int socket, struct sockaddr *address, + socklen_t *address_len, int flags) { + __rtsan_notify_intercepted_call("accept4"); + return REAL(accept4)(socket, address, address_len, flags); +} +#define RTSAN_MAYBE_INTERCEPT_ACCEPT4 INTERCEPT_FUNCTION(accept4) +#else +#define RTSAN_MAYBE_INTERCEPT_ACCEPT4 +#endif + // I/O Multiplexing INTERCEPTOR(int, poll, struct pollfd *fds, nfds_t nfds, int timeout) { @@ -776,6 +824,17 @@ INTERCEPTOR(int, epoll_pwait, int epfd, struct epoll_event *events, #define RTSAN_MAYBE_INTERCEPT_EPOLL_PWAIT #endif // SANITIZER_INTERCEPT_EPOLL +#if SANITIZER_INTERCEPT_PPOLL +INTERCEPTOR(int, ppoll, struct pollfd *fds, nfds_t n, const struct timespec *ts, + const sigset_t *set) { + __rtsan_notify_intercepted_call("ppoll"); + return REAL(ppoll)(fds, n, ts, set); +} +#define RTSAN_MAYBE_INTERCEPT_PPOLL INTERCEPT_FUNCTION(ppoll) +#else +#define RTSAN_MAYBE_INTERCEPT_PPOLL +#endif + #if SANITIZER_INTERCEPT_KQUEUE INTERCEPTOR(int, kqueue, void) { __rtsan_notify_intercepted_call("kqueue"); @@ -893,6 +952,7 @@ void __rtsan::InitializeInterceptors() { INTERCEPT_FUNCTION(close); INTERCEPT_FUNCTION(fopen); RTSAN_MAYBE_INTERCEPT_FOPEN64; + RTSAN_MAYBE_INTERCEPT_FREOPEN64; INTERCEPT_FUNCTION(fread); INTERCEPT_FUNCTION(read); INTERCEPT_FUNCTION(write); @@ -910,6 +970,10 @@ void __rtsan::InitializeInterceptors() { RTSAN_MAYBE_INTERCEPT_CREAT64; INTERCEPT_FUNCTION(puts); INTERCEPT_FUNCTION(fputs); + INTERCEPT_FUNCTION(fdopen); + INTERCEPT_FUNCTION(freopen); + RTSAN_MAYBE_INTERCEPT_OPEN_MEMSTREAM; + RTSAN_MAYBE_INTERCEPT_FMEMOPEN; INTERCEPT_FUNCTION(lseek); RTSAN_MAYBE_INTERCEPT_LSEEK64; INTERCEPT_FUNCTION(dup); @@ -956,6 +1020,7 @@ void __rtsan::InitializeInterceptors() { INTERCEPT_FUNCTION(sendto); INTERCEPT_FUNCTION(shutdown); INTERCEPT_FUNCTION(socket); + RTSAN_MAYBE_INTERCEPT_ACCEPT4; RTSAN_MAYBE_INTERCEPT_SELECT; INTERCEPT_FUNCTION(pselect); @@ -965,6 +1030,7 @@ void __rtsan::InitializeInterceptors() { RTSAN_MAYBE_INTERCEPT_EPOLL_CTL; RTSAN_MAYBE_INTERCEPT_EPOLL_WAIT; RTSAN_MAYBE_INTERCEPT_EPOLL_PWAIT; + RTSAN_MAYBE_INTERCEPT_PPOLL; RTSAN_MAYBE_INTERCEPT_KQUEUE; RTSAN_MAYBE_INTERCEPT_KEVENT; RTSAN_MAYBE_INTERCEPT_KEVENT64; diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp index 88df8ec46d0a..b052dd859dcd 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp @@ -353,6 +353,31 @@ TEST_F(RtsanFileTest, FopenDiesWhenRealtime) { ExpectNonRealtimeSurvival(Func); } +#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM +TEST_F(RtsanFileTest, OpenMemstreamDiesWhenRealtime) { + char *buffer; + size_t size; + auto Func = [&buffer, &size]() { + FILE *f = open_memstream(&buffer, &size); + EXPECT_THAT(f, Ne(nullptr)); + }; + + ExpectRealtimeDeath(Func, "open_memstream"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanFileTest, FmemOpenDiesWhenRealtime) { + char buffer[1024]; + auto Func = [&buffer]() { + FILE *f = fmemopen(&buffer, sizeof(buffer), "w"); + EXPECT_THAT(f, Ne(nullptr)); + }; + + ExpectRealtimeDeath(Func, "fmemopen"); + ExpectNonRealtimeSurvival(Func); +} +#endif + class RtsanOpenedFileTest : public RtsanFileTest { protected: void SetUp() override { @@ -391,6 +416,26 @@ TEST_F(RtsanOpenedFileTest, IoctlBehavesWithOutputArg) { EXPECT_THAT(arg, Ge(0)); } +TEST_F(RtsanOpenedFileTest, FdopenDiesWhenRealtime) { + auto Func = [&]() { + FILE *f = fdopen(GetOpenFd(), "w"); + EXPECT_THAT(f, Ne(nullptr)); + }; + + ExpectRealtimeDeath(Func, "fdopen"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanOpenedFileTest, FreopenDiesWhenRealtime) { + auto Func = [&]() { + FILE *newfile = freopen(GetTemporaryFilePath(), "w", GetOpenFile()); + EXPECT_THAT(newfile, Ne(nullptr)); + }; + + ExpectRealtimeDeath(Func, MAYBE_APPEND_64("freopen")); + ExpectNonRealtimeSurvival(Func); +} + TEST(TestRtsanInterceptors, IoctlBehavesWithOutputPointer) { // These initial checks just see if we CAN run these tests. // If we can't (can't open a socket, or can't find an interface, just @@ -860,6 +905,16 @@ TEST(TestRtsanInterceptors, AcceptingASocketDiesWhenRealtime) { ExpectNonRealtimeSurvival(Func); } +#if SANITIZER_INTERCEPT_ACCEPT4 +TEST(TestRtsanInterceptors, Accepting4ASocketDiesWhenRealtime) { + auto Func = []() { + EXPECT_LT(accept4(kNotASocketFd, nullptr, nullptr, 0), 0); + }; + ExpectRealtimeDeath(Func, "accept4"); + ExpectNonRealtimeSurvival(Func); +} +#endif + TEST(TestRtsanInterceptors, ConnectingASocketDiesWhenRealtime) { auto Func = []() { EXPECT_NE(connect(kNotASocketFd, nullptr, 0), 0); }; ExpectRealtimeDeath(Func, "connect"); @@ -1026,6 +1081,21 @@ TEST_F(EpollTest, EpollPWaitDiesWhenRealtime) { } #endif // SANITIZER_INTERCEPT_EPOLL +#if SANITIZER_INTERCEPT_PPOLL +TEST(TestRtsanInterceptors, PpollDiesWhenRealtime) { + struct pollfd fds[1]; + fds[0].fd = 0; + fds[0].events = POLLIN; + + timespec ts = {0, 0}; + + auto Func = [&fds, &ts]() { ppoll(fds, 1, &ts, nullptr); }; + + ExpectRealtimeDeath(Func, "ppoll"); + ExpectNonRealtimeSurvival(Func); +} +#endif + #if SANITIZER_INTERCEPT_KQUEUE TEST(TestRtsanInterceptors, KqueueDiesWhenRealtime) { auto Func = []() { kqueue(); }; diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp index 50c726e09f28..ca560fc21035 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp @@ -19,7 +19,10 @@ extern "C" const char *__rtsan_default_options() { // and make sure we do not overwhelm the syslog while testing. Also, let's // turn symbolization off to speed up testing, especially when not running // with llvm-symbolizer but with atos. - return "symbolize=false:abort_on_error=0:log_to_syslog=0"; + return "symbolize=false:" + "abort_on_error=0:" + "log_to_syslog=0:" + "verify_interceptors=0:"; // some of our tests don't need interceptors #else // Let's turn symbolization off to speed up testing (more than 3 times speedup // observed). diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index ba3693dbd11f..24a8a2d4dc55 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -347,7 +347,7 @@ extern const short *_tolower_tab_; uptr copy_length = internal_strnlen(s, size); \ char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ if (common_flags()->intercept_strndup) { \ - COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ + COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min<uptr>(size, copy_length + 1)); \ } \ if (new_mem) { \ COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ @@ -445,7 +445,7 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #endif #if SANITIZER_INTERCEPT_STRNDUP -INTERCEPTOR(char*, strndup, const char *s, uptr size) { +INTERCEPTOR(char*, strndup, const char *s, usize size) { void *ctx; COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); } @@ -455,7 +455,7 @@ INTERCEPTOR(char*, strndup, const char *s, uptr size) { #endif // SANITIZER_INTERCEPT_STRNDUP #if SANITIZER_INTERCEPT___STRNDUP -INTERCEPTOR(char*, __strndup, const char *s, uptr size) { +INTERCEPTOR(char*, __strndup, const char *s, usize size) { void *ctx; COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); } @@ -511,23 +511,23 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { } DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc, - const char *s1, const char *s2, uptr n, + const char *s1, const char *s2, usize n, int result) -INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { +INTERCEPTOR(int, strncmp, const char *s1, const char *s2, usize size) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strncmp(s1, s2, size); void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size); unsigned char c1 = 0, c2 = 0; - uptr i; + usize i; for (i = 0; i < size; i++) { c1 = (unsigned char)s1[i]; c2 = (unsigned char)s2[i]; if (c1 != c2 || c1 == '\0') break; } - uptr i1 = i; - uptr i2 = i; + usize i1 = i; + usize i2 = i; if (common_flags()->strict_string_checks) { for (; i1 < size && s1[i1]; i1++) {} for (; i2 < size && s2[i2]; i2++) {} @@ -576,21 +576,21 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { } DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc, - const char *s1, const char *s2, uptr size, + const char *s1, const char *s2, usize size, int result) INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T size) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, size); unsigned char c1 = 0, c2 = 0; - uptr i; + usize i; for (i = 0; i < size; i++) { c1 = (unsigned char)s1[i]; c2 = (unsigned char)s2[i]; if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; } - uptr i1 = i; - uptr i2 = i; + usize i1 = i; + usize i2 = i; if (common_flags()->strict_string_checks) { for (; i1 < size && s1[i1]; i1++) {} for (; i2 < size && s2[i2]; i2++) {} @@ -833,13 +833,13 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { #if SANITIZER_INTERCEPT_MEMCMP DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc, - const void *s1, const void *s2, uptr n, + const void *s1, const void *s2, usize n, int result) // Common code for `memcmp` and `bcmp`. int MemcmpInterceptorCommon(void *ctx, - int (*real_fn)(const void *, const void *, uptr), - const void *a1, const void *a2, uptr size) { + int (*real_fn)(const void *, const void *, usize), + const void *a1, const void *a2, usize size) { if (common_flags()->intercept_memcmp) { if (common_flags()->strict_memcmp) { // Check the entire regions even if the first bytes of the buffers are @@ -851,7 +851,7 @@ int MemcmpInterceptorCommon(void *ctx, unsigned char c1 = 0, c2 = 0; const unsigned char *s1 = (const unsigned char*)a1; const unsigned char *s2 = (const unsigned char*)a2; - uptr i; + usize i; for (i = 0; i < size; i++) { c1 = s1[i]; c2 = s2[i]; @@ -871,7 +871,7 @@ int MemcmpInterceptorCommon(void *ctx, return result; } -INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, usize size) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_memcmp(a1, a2, size); void *ctx; @@ -885,7 +885,7 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { #endif #if SANITIZER_INTERCEPT_BCMP -INTERCEPTOR(int, bcmp, const void *a1, const void *a2, uptr size) { +INTERCEPTOR(int, bcmp, const void *a1, const void *a2, usize size) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_memcmp(a1, a2, size); void *ctx; @@ -1138,7 +1138,7 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { #endif #if SANITIZER_INTERCEPT_FWRITE -INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) { +INTERCEPTOR(SIZE_T, fwrite, const void *p, usize size, usize nmemb, void *file) { // libc file streams can call user-supplied functions, see fopencookie. void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file); @@ -1313,7 +1313,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg5), sizeof(u64)); } else if (res != -1 && option == PR_GET_PDEATHSIG) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg2), sizeof(int)); -# if !SANITIZER_ANDROID +# if SANITIZER_GLIBC } else if (res != -1 && option == PR_SET_SECCOMP && arg2 == SECCOMP_MODE_FILTER) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg3), struct_sock_fprog_sz); @@ -6553,12 +6553,12 @@ static void MlockIsUnsupported() { SanitizerToolName); } -INTERCEPTOR(int, mlock, const void *addr, uptr len) { +INTERCEPTOR(int, mlock, const void *addr, usize len) { MlockIsUnsupported(); return 0; } -INTERCEPTOR(int, munlock, const void *addr, uptr len) { +INTERCEPTOR(int, munlock, const void *addr, usize len) { MlockIsUnsupported(); return 0; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc index 52e489d02cda..1565a494140f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @@ -82,7 +82,7 @@ #endif #if SANITIZER_INTERCEPT_MEMSET -INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { +INTERCEPTOR(void *, memset, void *dst, int v, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size); } @@ -93,7 +93,7 @@ INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { #endif #if SANITIZER_INTERCEPT_MEMMOVE -INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { +INTERCEPTOR(void *, memmove, void *dst, const void *src, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); } @@ -104,7 +104,7 @@ INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { #endif #if SANITIZER_INTERCEPT_MEMCPY -INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { +INTERCEPTOR(void *, memcpy, void *dst, const void *src, usize size) { // On OS X, calling internal_memcpy here will cause memory corruptions, // because memcpy and memmove are actually aliases of the same // implementation. We need to use internal_memmove here. @@ -133,63 +133,63 @@ INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { #endif #if SANITIZER_INTERCEPT_AEABI_MEM -INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); } -INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); } -INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); } -INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); } -INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); } -INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) { +INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); } // Note the argument order. -INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) { +INTERCEPTOR(void *, __aeabi_memset, void *block, usize size, int c) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); } -INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) { +INTERCEPTOR(void *, __aeabi_memset4, void *block, usize size, int c) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); } -INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) { +INTERCEPTOR(void *, __aeabi_memset8, void *block, usize size, int c) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); } -INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) { +INTERCEPTOR(void *, __aeabi_memclr, void *block, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); } -INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) { +INTERCEPTOR(void *, __aeabi_memclr4, void *block, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); } -INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) { +INTERCEPTOR(void *, __aeabi_memclr8, void *block, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); } @@ -212,7 +212,7 @@ INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) { #endif // SANITIZER_INTERCEPT_AEABI_MEM #if SANITIZER_INTERCEPT___BZERO -INTERCEPTOR(void *, __bzero, void *block, uptr size) { +INTERCEPTOR(void *, __bzero, void *block, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); } @@ -222,7 +222,7 @@ INTERCEPTOR(void *, __bzero, void *block, uptr size) { #endif // SANITIZER_INTERCEPT___BZERO #if SANITIZER_INTERCEPT_BZERO -INTERCEPTOR(void *, bzero, void *block, uptr size) { +INTERCEPTOR(void *, bzero, void *block, usize size) { void *ctx; COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index 9208b12552ff..fff60c96f632 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -203,6 +203,12 @@ typedef __SIZE_TYPE__ usize; typedef uptr usize; #endif +#if defined(__s390__) && !defined(__s390x__) +typedef long ssize; +#else +typedef sptr ssize; +#endif + typedef u64 tid_t; // ----------- ATTENTION ------------- diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index 26d2e8d4ed76..c8a0afccb254 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -972,8 +972,9 @@ static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; LowLevelAllocator allocator_for_env; static bool ShouldCheckInterceptors() { - // Restrict "interceptors working?" check to ASan and TSan. - const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer"}; + // Restrict "interceptors working?" check + const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer", + "RealtimeSanitizer"}; size_t count = sizeof(sanitizer_names) / sizeof(sanitizer_names[0]); for (size_t i = 0; i < count; i++) { if (internal_strcmp(sanitizer_names[i], SanitizerToolName) == 0) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 7d98f8e9a9d8..ea0933ca64af 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -313,7 +313,7 @@ extern unsigned struct_statvfs_sz; struct __sanitizer_iovec { void *iov_base; - uptr iov_len; + usize iov_len; }; #if !SANITIZER_ANDROID @@ -523,6 +523,7 @@ struct __sanitizer_dirent64 { unsigned short d_reclen; // more fields that we don't care about }; +extern unsigned struct_sock_fprog_sz; #endif #if defined(__x86_64__) && !defined(_LP64) @@ -600,7 +601,7 @@ struct __sanitizer_siginfo_pad { #if SANITIZER_LINUX # define SANITIZER_HAS_SIGINFO 1 union __sanitizer_siginfo { - struct { + __extension__ struct { int si_signo; # if SANITIZER_MIPS int si_code; @@ -1076,7 +1077,6 @@ extern unsigned struct_serial_struct_sz; extern unsigned struct_sockaddr_ax25_sz; extern unsigned struct_unimapdesc_sz; extern unsigned struct_unimapinit_sz; -extern unsigned struct_sock_fprog_sz; # endif // SANITIZER_LINUX && !SANITIZER_ANDROID extern const unsigned long __sanitizer_bufsiz; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index ea513d5f263f..fd0f989ee392 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -164,7 +164,24 @@ void UnmapOrDie(void *addr, uptr size, bool raw_report) { static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, const char *mmap_type) { error_t last_error = GetLastError(); - if (last_error == ERROR_NOT_ENOUGH_MEMORY) + + // Assumption: VirtualAlloc is the last system call that was invoked before + // this method. + // VirtualAlloc emits one of 3 error codes when running out of memory + // 1. ERROR_NOT_ENOUGH_MEMORY: + // There's not enough memory to execute the command + // 2. ERROR_INVALID_PARAMETER: + // VirtualAlloc will return this if the request would allocate memory at an + // address exceeding or being very close to the maximum application address + // (the `lpMaximumApplicationAddress` field within the `SystemInfo` struct). + // This does not seem to be officially documented, but is corroborated here: + // https://stackoverflow.com/questions/45833674/why-does-virtualalloc-fail-for-lpaddress-greater-than-0x6ffffffffff + // 3. ERROR_COMMITMENT_LIMIT: + // VirtualAlloc will return this if e.g. the pagefile is too small to commit + // the requested amount of memory. + if (last_error == ERROR_NOT_ENOUGH_MEMORY || + last_error == ERROR_INVALID_PARAMETER || + last_error == ERROR_COMMITMENT_LIMIT) return nullptr; ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); } diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt index dc700cec9bec..3f9ae866a755 100644 --- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt @@ -98,6 +98,7 @@ set(SCUDO_HEADERS tsd_exclusive.h tsd_shared.h tsd.h + type_traits.h vector.h wrappers_c_checks.h wrappers_c.h diff --git a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h index 5477236ac1f3..ea12a5b1447f 100644 --- a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h +++ b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h @@ -12,35 +12,7 @@ #include "condition_variable.h" #include "internal_defs.h" #include "secondary.h" - -namespace { - -template <typename T> struct removeConst { - using type = T; -}; -template <typename T> struct removeConst<const T> { - using type = T; -}; - -// This is only used for SFINAE when detecting if a type is defined. -template <typename T> struct voidAdaptor { - using type = void; -}; - -// This is used for detecting the case that defines the flag with wrong type and -// it'll be viewed as undefined optional flag. -template <typename L, typename R> struct assertSameType { - template <typename, typename> struct isSame { - static constexpr bool value = false; - }; - template <typename T> struct isSame<T, T> { - static constexpr bool value = true; - }; - static_assert(isSame<L, R>::value, "Flag type mismatches"); - using type = R; -}; - -} // namespace +#include "type_traits.h" namespace scudo { diff --git a/compiler-rt/lib/scudo/standalone/list.h b/compiler-rt/lib/scudo/standalone/list.h index c6bd32a8fa32..e0b82788251b 100644 --- a/compiler-rt/lib/scudo/standalone/list.h +++ b/compiler-rt/lib/scudo/standalone/list.h @@ -10,17 +10,7 @@ #define SCUDO_LIST_H_ #include "internal_defs.h" - -// TODO: Move the helpers to a header. -namespace { -template <typename T> struct isPointer { - static constexpr bool value = false; -}; - -template <typename T> struct isPointer<T *> { - static constexpr bool value = true; -}; -} // namespace +#include "type_traits.h" namespace scudo { @@ -58,10 +48,11 @@ public: template <class T> class LinkOp<T, /*LinkWithPtr=*/false> { public: - using LinkTy = decltype(T::Next); + using LinkTy = typename assertSameType< + typename removeConst<decltype(T::Next)>::type, + typename removeConst<decltype(T::EndOfListVal)>::type>::type; LinkOp() = default; - // TODO: Check if the `BaseSize` can fit in `Size`. LinkOp(T *BaseT, uptr BaseSize) : Base(BaseT), Size(static_cast<LinkTy>(BaseSize)) {} void init(T *LinkBase, uptr BaseSize) { @@ -80,11 +71,12 @@ public: } // Set `X->Next` to `Next`. void setNext(T *X, T *Next) const { - // TODO: Check if the offset fits in the size of `LinkTy`. - if (Next == nullptr) + if (Next == nullptr) { X->Next = getEndOfListVal(); - else + } else { + assertElementInRange(Next); X->Next = static_cast<LinkTy>(Next - Base); + } } T *getPrev(T *X) const { @@ -96,17 +88,22 @@ public: } // Set `X->Prev` to `Prev`. void setPrev(T *X, T *Prev) const { - DCHECK_LT(reinterpret_cast<uptr>(Prev), - reinterpret_cast<uptr>(Base + Size)); - if (Prev == nullptr) + if (Prev == nullptr) { X->Prev = getEndOfListVal(); - else + } else { + assertElementInRange(Prev); X->Prev = static_cast<LinkTy>(Prev - Base); + } } - // TODO: `LinkTy` should be the same as decltype(T::EndOfListVal). LinkTy getEndOfListVal() const { return T::EndOfListVal; } +private: + void assertElementInRange(T *X) const { + DCHECK_GE(reinterpret_cast<uptr>(X), reinterpret_cast<uptr>(Base)); + DCHECK_LE(static_cast<LinkTy>(X - Base), Size); + } + protected: T *Base = nullptr; LinkTy Size = 0; diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h index 654b129d9f54..596c48f004b2 100644 --- a/compiler-rt/lib/scudo/standalone/primary32.h +++ b/compiler-rt/lib/scudo/standalone/primary32.h @@ -387,7 +387,7 @@ private: struct ReleaseToOsInfo { uptr BytesInFreeListAtLastCheckpoint; - uptr RangesReleased; + uptr NumReleasesAttempted; uptr LastReleasedBytes; u64 LastReleaseAtNs; }; @@ -880,14 +880,14 @@ private: BytesInFreeList - Sci->ReleaseInfo.BytesInFreeListAtLastCheckpoint; } const uptr AvailableChunks = Sci->AllocatedUser / BlockSize; - Str->append(" %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu " - "inuse: %6zu avail: %6zu releases: %6zu last released: %6zuK " - "latest pushed bytes: %6zuK\n", - ClassId, getSizeByClassId(ClassId), Sci->AllocatedUser >> 10, - Sci->FreeListInfo.PoppedBlocks, Sci->FreeListInfo.PushedBlocks, - InUse, AvailableChunks, Sci->ReleaseInfo.RangesReleased, - Sci->ReleaseInfo.LastReleasedBytes >> 10, - PushedBytesDelta >> 10); + Str->append( + " %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu " + "inuse: %6zu avail: %6zu releases attempted: %6zu last released: %6zuK " + "latest pushed bytes: %6zuK\n", + ClassId, getSizeByClassId(ClassId), Sci->AllocatedUser >> 10, + Sci->FreeListInfo.PoppedBlocks, Sci->FreeListInfo.PushedBlocks, InUse, + AvailableChunks, Sci->ReleaseInfo.NumReleasesAttempted, + Sci->ReleaseInfo.LastReleasedBytes >> 10, PushedBytesDelta >> 10); } void getSizeClassFragmentationInfo(SizeClassInfo *Sci, uptr ClassId, @@ -972,6 +972,10 @@ private: const uptr Base = First * RegionSize; const uptr NumberOfRegions = Last - First + 1U; + // The following steps contribute to the majority time spent in page + // releasing thus we increment the counter here. + ++Sci->ReleaseInfo.NumReleasesAttempted; + // ==================================================================== // // 2. Mark the free blocks and we can tell which pages are in-use by // querying `PageReleaseContext`. @@ -991,9 +995,8 @@ private: }; releaseFreeMemoryToOS(Context, Recorder, SkipRegion); - if (Recorder.getReleasedRangesCount() > 0) { + if (Recorder.getReleasedBytes() > 0) { Sci->ReleaseInfo.BytesInFreeListAtLastCheckpoint = BytesInFreeList; - Sci->ReleaseInfo.RangesReleased += Recorder.getReleasedRangesCount(); Sci->ReleaseInfo.LastReleasedBytes = Recorder.getReleasedBytes(); TotalReleasedBytes += Sci->ReleaseInfo.LastReleasedBytes; } diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h index e382e01f5d8e..2b520ceb3314 100644 --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -530,7 +530,7 @@ private: struct ReleaseToOsInfo { uptr BytesInFreeListAtLastCheckpoint; - uptr RangesReleased; + uptr NumReleasesAttempted; uptr LastReleasedBytes; // The minimum size of pushed blocks to trigger page release. uptr TryReleaseThreshold; @@ -1144,11 +1144,12 @@ private: Str->append( "%s %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu " "inuse: %6zu total: %6zu releases: %6zu last " - "released: %6zuK latest pushed bytes: %6zuK region: 0x%zx (0x%zx)\n", + "releases attempted: %6zuK latest pushed bytes: %6zuK region: 0x%zx " + "(0x%zx)\n", Region->Exhausted ? "E" : " ", ClassId, getSizeByClassId(ClassId), Region->MemMapInfo.MappedUser >> 10, Region->FreeListInfo.PoppedBlocks, Region->FreeListInfo.PushedBlocks, InUseBlocks, TotalChunks, - Region->ReleaseInfo.RangesReleased, + Region->ReleaseInfo.NumReleasesAttempted, Region->ReleaseInfo.LastReleasedBytes >> 10, RegionPushedBytesDelta >> 10, Region->RegionBeg, getRegionBaseByClassId(ClassId)); @@ -1322,7 +1323,7 @@ private: Context.getReleaseOffset()); auto SkipRegion = [](UNUSED uptr RegionIndex) { return false; }; releaseFreeMemoryToOS(Context, Recorder, SkipRegion); - if (Recorder.getReleasedRangesCount() > 0) { + if (Recorder.getReleasedBytes() > 0) { // This is the case that we didn't hit the release threshold but it has // been past a certain period of time. Thus we try to release some pages // and if it does release some additional pages, it's hint that we are @@ -1342,7 +1343,6 @@ private: } Region->ReleaseInfo.BytesInFreeListAtLastCheckpoint = BytesInFreeList; - Region->ReleaseInfo.RangesReleased += Recorder.getReleasedRangesCount(); Region->ReleaseInfo.LastReleasedBytes = Recorder.getReleasedBytes(); } Region->ReleaseInfo.LastReleaseAtNs = getMonotonicTimeFast(); diff --git a/compiler-rt/lib/scudo/standalone/release.h b/compiler-rt/lib/scudo/standalone/release.h index 6353dafde316..7a4912ec0b5a 100644 --- a/compiler-rt/lib/scudo/standalone/release.h +++ b/compiler-rt/lib/scudo/standalone/release.h @@ -22,8 +22,6 @@ public: RegionReleaseRecorder(MemMapT *RegionMemMap, uptr Base, uptr Offset = 0) : RegionMemMap(RegionMemMap), Base(Base), Offset(Offset) {} - uptr getReleasedRangesCount() const { return ReleasedRangesCount; } - uptr getReleasedBytes() const { return ReleasedBytes; } uptr getBase() const { return Base; } @@ -33,12 +31,10 @@ public: void releasePageRangeToOS(uptr From, uptr To) { const uptr Size = To - From; RegionMemMap->releasePagesToOS(getBase() + Offset + From, Size); - ReleasedRangesCount++; ReleasedBytes += Size; } private: - uptr ReleasedRangesCount = 0; uptr ReleasedBytes = 0; MemMapT *RegionMemMap = nullptr; uptr Base = 0; @@ -52,8 +48,6 @@ public: ReleaseRecorder(uptr Base, uptr Offset = 0, MapPlatformData *Data = nullptr) : Base(Base), Offset(Offset), Data(Data) {} - uptr getReleasedRangesCount() const { return ReleasedRangesCount; } - uptr getReleasedBytes() const { return ReleasedBytes; } uptr getBase() const { return Base; } @@ -62,12 +56,10 @@ public: void releasePageRangeToOS(uptr From, uptr To) { const uptr Size = To - From; releasePagesToOS(Base, From + Offset, Size, Data); - ReleasedRangesCount++; ReleasedBytes += Size; } private: - uptr ReleasedRangesCount = 0; uptr ReleasedBytes = 0; // The starting address to release. Note that we may want to combine (Base + // Offset) as a new Base. However, the Base is retrieved from diff --git a/compiler-rt/lib/scudo/standalone/type_traits.h b/compiler-rt/lib/scudo/standalone/type_traits.h new file mode 100644 index 000000000000..16ed5a048f82 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/type_traits.h @@ -0,0 +1,47 @@ +//===-- type_traits.h -------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TYPE_TRAITS_H_ +#define SCUDO_TYPE_TRAITS_H_ + +namespace scudo { + +template <typename T> struct removeConst { + using type = T; +}; +template <typename T> struct removeConst<const T> { + using type = T; +}; + +// This is only used for SFINAE when detecting if a type is defined. +template <typename T> struct voidAdaptor { + using type = void; +}; + +template <typename L, typename R> struct assertSameType { + template <typename, typename> struct isSame { + static constexpr bool value = false; + }; + template <typename T> struct isSame<T, T> { + static constexpr bool value = true; + }; + static_assert(isSame<L, R>::value, "Type mismatches"); + using type = R; +}; + +template <typename T> struct isPointer { + static constexpr bool value = false; +}; + +template <typename T> struct isPointer<T *> { + static constexpr bool value = true; +}; + +} // namespace scudo + +#endif // SCUDO_TYPE_TRAITS_H_ diff --git a/compiler-rt/lib/tsan/rtl/CMakeLists.txt b/compiler-rt/lib/tsan/rtl/CMakeLists.txt index f40e72dbde1f..d7d84706bfd5 100644 --- a/compiler-rt/lib/tsan/rtl/CMakeLists.txt +++ b/compiler-rt/lib/tsan/rtl/CMakeLists.txt @@ -259,7 +259,6 @@ else() STATIC ARCHS ${arch} SOURCES ${TSAN_CXX_SOURCES} - $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> ADDITIONAL_HEADERS ${TSAN_HEADERS} CFLAGS ${TSAN_RTL_CFLAGS} PARENT_TARGET tsan) diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp index 423d97e94d81..f671c8167a3c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -97,7 +97,7 @@ extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); extern "C" int pthread_setspecific(unsigned key, const void *v); DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) -DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize size) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) extern "C" int pthread_equal(void *t1, void *t2); extern "C" void *pthread_self(); @@ -768,7 +768,7 @@ TSAN_INTERCEPTOR(char *, strcpy, char *dst, const char *src) { return REAL(strcpy)(dst, src); } -TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { +TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, usize n) { SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n); uptr srclen = internal_strnlen(src, n); MemoryAccessRange(thr, pc, (uptr)dst, n, true); diff --git a/compiler-rt/lib/tysan/CMakeLists.txt b/compiler-rt/lib/tysan/CMakeLists.txt new file mode 100644 index 000000000000..7d13ae396391 --- /dev/null +++ b/compiler-rt/lib/tysan/CMakeLists.txt @@ -0,0 +1,79 @@ +include_directories(..) + +# Runtime library sources and build flags. +set(TYSAN_SOURCES + tysan.cpp + tysan_interceptors.cpp + ) + +SET(TYSAN_HEADERS + tysan.h + tysan_flags.inc + tysan_platform.h + ) + +set(TYSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF TYSAN_COMMON_CFLAGS) +# Prevent clang from generating libc calls. +append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding TYSAN_COMMON_CFLAGS) +set(TYSAN_DYNAMIC_CFLAGS ${TYSAN_COMMON_CFLAGS}) + +set(TYSAN_COMMON_DEFINITIONS "") +set(TYSAN_DYNAMIC_DEFINITIONS ${TYSAN_COMMON_DEFINITIONS} TYSAN_DYNAMIC=1) + +# Compile TYSan sources into an object library. + +add_compiler_rt_object_libraries(RTTysan_dynamic + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + SOURCES ${TYSAN_SOURCES} + ADDITIONAL_HEADERS ${TYSAN_HEADERS} + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS}) + + +# Static runtime library. +add_compiler_rt_component(tysan) + + +if(APPLE) + add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) + + add_compiler_rt_runtime(clang_rt.tysan + SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_dynamic + RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTSanitizerCommonSymbolizer + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET tysan) + + add_compiler_rt_runtime(clang_rt.tysan_static + STATIC + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_static + CFLAGS ${TYSAN_CFLAGS} + DEFS ${TYSAN_COMMON_DEFINITIONS} + PARENT_TARGET tysan) +else() + set(TYSAN_CFLAGS ${TYSAN_COMMON_CFLAGS}) + append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TYSAN_CFLAGS) + + foreach(arch ${TYSAN_SUPPORTED_ARCH}) + add_compiler_rt_runtime(clang_rt.tysan + STATIC + ARCHS ${arch} + SOURCES ${TYSAN_SOURCES} + OBJECT_LIBS RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTSanitizerCommonSymbolizer + CFLAGS ${TYSAN_CFLAGS} + PARENT_TARGET tysan) + endforeach() +endif() diff --git a/compiler-rt/lib/tysan/lit.cfg b/compiler-rt/lib/tysan/lit.cfg new file mode 100644 index 000000000000..e3ef6c9c9714 --- /dev/null +++ b/compiler-rt/lib/tysan/lit.cfg @@ -0,0 +1,35 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'TypeSanitizer' + getattr(config, 'name_suffix', 'default') + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Setup default compiler flags used with -fsanitize=type option. +clang_tysan_cflags = (["-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls"] + + config.target_cflags + + config.debug_info_flags) +clang_tysan_cxxflags = config.cxx_mode_flags + clang_tysan_cflags + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) ) +config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +# TypeSanitizer tests are currently supported on Linux only. +if config.host_os not in ['Linux']: + config.unsupported = True + +if config.target_arch != 'aarch64': + config.available_features.add('stable-runtime') + diff --git a/compiler-rt/lib/tysan/lit.site.cfg.in b/compiler-rt/lib/tysan/lit.site.cfg.in new file mode 100644 index 000000000000..673d04e51437 --- /dev/null +++ b/compiler-rt/lib/tysan/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg") diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp new file mode 100644 index 000000000000..39d78e7c95e0 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -0,0 +1,346 @@ +//===-- tysan.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 TypeSanitizer. +// +// TypeSanitizer runtime. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +#include "tysan/tysan.h" + +#include <string.h> + +using namespace __sanitizer; +using namespace __tysan; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_set_type_unknown(const void *addr, uptr size) { + if (tysan_inited) + internal_memset(shadow_for(addr), 0, size * sizeof(uptr)); +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_copy_types(const void *daddr, const void *saddr, uptr size) { + if (tysan_inited) + internal_memmove(shadow_for(daddr), shadow_for(saddr), size * sizeof(uptr)); +} + +static const char *getDisplayName(const char *Name) { + if (Name[0] == '\0') + return "<anonymous type>"; + + // Clang generates tags for C++ types that demangle as typeinfo. Remove the + // prefix from the generated string. + const char *TIPrefix = "typeinfo name for "; + size_t TIPrefixLen = strlen(TIPrefix); + + const char *DName = Symbolizer::GetOrInit()->Demangle(Name); + if (!internal_strncmp(DName, TIPrefix, TIPrefixLen)) + DName += TIPrefixLen; + + return DName; +} + +static void printTDName(tysan_type_descriptor *td) { + if (((sptr)td) <= 0) { + Printf("<unknown type>"); + return; + } + + switch (td->Tag) { + default: + CHECK(false && "invalid enum value"); + break; + case TYSAN_MEMBER_TD: + printTDName(td->Member.Access); + if (td->Member.Access != td->Member.Base) { + Printf(" (in "); + printTDName(td->Member.Base); + Printf(" at offset %zu)", td->Member.Offset); + } + break; + case TYSAN_STRUCT_TD: + Printf("%s", getDisplayName( + (char *)(td->Struct.Members + td->Struct.MemberCount))); + break; + } +} + +static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) { + tysan_type_descriptor *RootTD = TD; + + do { + RootTD = TD; + + if (TD->Tag == TYSAN_STRUCT_TD) { + if (TD->Struct.MemberCount > 0) + TD = TD->Struct.Members[0].Type; + else + TD = nullptr; + } else if (TD->Tag == TYSAN_MEMBER_TD) { + TD = TD->Member.Access; + } else { + CHECK(false && "invalid enum value"); + break; + } + } while (TD); + + return RootTD; +} + +static bool isAliasingLegalUp(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset) { + // Walk up the tree starting with TDA to see if we reach TDB. + uptr OffsetA = 0, OffsetB = 0; + if (TDB->Tag == TYSAN_MEMBER_TD) { + OffsetB = TDB->Member.Offset; + TDB = TDB->Member.Base; + } + + if (TDA->Tag == TYSAN_MEMBER_TD) { + OffsetA = TDA->Member.Offset - TDAOffset; + TDA = TDA->Member.Base; + } + + do { + if (TDA == TDB) + return OffsetA == OffsetB; + + if (TDA->Tag == TYSAN_STRUCT_TD) { + // Reached root type descriptor. + if (!TDA->Struct.MemberCount) + break; + + uptr Idx = 0; + for (; Idx < TDA->Struct.MemberCount - 1; ++Idx) { + if (TDA->Struct.Members[Idx].Offset >= OffsetA) + break; + } + + OffsetA -= TDA->Struct.Members[Idx].Offset; + TDA = TDA->Struct.Members[Idx].Type; + } else { + CHECK(false && "invalid enum value"); + break; + } + } while (TDA); + + return false; +} + +static bool isAliasingLegal(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset = 0) { + if (TDA == TDB || !TDB || !TDA) + return true; + + // Aliasing is legal is the two types have different root nodes. + if (getRootTD(TDA) != getRootTD(TDB)) + return true; + + // TDB may have been adjusted by offset TDAOffset in the caller to point to + // the outer type. Check for aliasing with and without adjusting for this + // offset. + return isAliasingLegalUp(TDA, TDB, 0) || isAliasingLegalUp(TDB, TDA, 0) || + isAliasingLegalUp(TDA, TDB, TDAOffset); +} + +namespace __tysan { +class Decorator : public __sanitizer::SanitizerCommonDecorator { +public: + Decorator() : SanitizerCommonDecorator() {} + const char *Warning() { return Red(); } + const char *Name() { return Green(); } + const char *End() { return Default(); } +}; +} // namespace __tysan + +ALWAYS_INLINE +static void reportError(void *Addr, int Size, tysan_type_descriptor *TD, + tysan_type_descriptor *OldTD, const char *AccessStr, + const char *DescStr, int Offset, uptr pc, uptr bp, + uptr sp) { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: TypeSanitizer: type-aliasing-violation on address %p" + " (pc %p bp %p sp %p tid %llu)\n", + Addr, (void *)pc, (void *)bp, (void *)sp, GetTid()); + Printf("%s", d.End()); + Printf("%s of size %d at %p with type ", AccessStr, Size, Addr); + + Printf("%s", d.Name()); + printTDName(TD); + Printf("%s", d.End()); + + Printf(" %s of type ", DescStr); + + Printf("%s", d.Name()); + printTDName(OldTD); + Printf("%s", d.End()); + + if (Offset != 0) + Printf(" that starts at offset %d\n", Offset); + else + Printf("\n"); + + if (pc) { + + bool request_fast = StackTrace::WillUseFastUnwind(true); + BufferedStackTrace ST; + ST.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, request_fast); + ST.Print(); + } else { + Printf("\n"); + } +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { + GET_CALLER_PC_BP_SP; + + bool IsRead = flags & 1; + bool IsWrite = flags & 2; + const char *AccessStr; + if (IsRead && !IsWrite) + AccessStr = "READ"; + else if (!IsRead && IsWrite) + AccessStr = "WRITE"; + else + AccessStr = "ATOMIC UPDATE"; + + tysan_type_descriptor **OldTDPtr = shadow_for(addr); + tysan_type_descriptor *OldTD = *OldTDPtr; + if (((sptr)OldTD) < 0) { + int i = -((sptr)OldTD); + OldTDPtr -= i; + OldTD = *OldTDPtr; + + if (!isAliasingLegal(td, OldTD, i)) + reportError(addr, size, td, OldTD, AccessStr, + "accesses part of an existing object", -i, pc, bp, sp); + + return; + } + + if (!isAliasingLegal(td, OldTD)) { + reportError(addr, size, td, OldTD, AccessStr, "accesses an existing object", + 0, pc, bp, sp); + return; + } + + // These types are allowed to alias (or the stored type is unknown), report + // an error if we find an interior type. + + for (int i = 0; i < size; ++i) { + OldTDPtr = shadow_for((void *)(((uptr)addr) + i)); + OldTD = *OldTDPtr; + if (((sptr)OldTD) >= 0 && !isAliasingLegal(td, OldTD)) + reportError(addr, size, td, OldTD, AccessStr, + "partially accesses an object", i, pc, bp, sp); + } +} + +Flags __tysan::flags_data; + +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address; +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_app_memory_mask; + +#ifdef TYSAN_RUNTIME_VMA +// Runtime detected VMA size. +int __tysan::vmaSize; +#endif + +void Flags::SetDefaults() { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void RegisterTySanFlags(FlagParser *parser, Flags *f) { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void InitializeFlags() { + SetCommonFlagsDefaults(); + { + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.external_symbolizer_path = GetEnv("TYSAN_SYMBOLIZER_PATH"); + OverrideCommonFlags(cf); + } + + flags().SetDefaults(); + + FlagParser parser; + RegisterCommonFlags(&parser); + RegisterTySanFlags(&parser, &flags()); + parser.ParseString(GetEnv("TYSAN_OPTIONS")); + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + parser.PrintFlagDescriptions(); +} + +static void TySanInitializePlatformEarly() { + AvoidCVE_2016_2143(); +#ifdef TYSAN_RUNTIME_VMA + vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); +#if defined(__aarch64__) && !SANITIZER_APPLE + if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) { + Printf("FATAL: TypeSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize); + Die(); + } +#endif +#endif + + __sanitizer::InitializePlatformEarly(); + + __tysan_shadow_memory_address = ShadowAddr(); + __tysan_app_memory_mask = AppMask(); +} + +namespace __tysan { +bool tysan_inited = false; +bool tysan_init_is_running; +} // namespace __tysan + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tysan_init() { + CHECK(!tysan_init_is_running); + if (tysan_inited) + return; + tysan_init_is_running = true; + + InitializeFlags(); + TySanInitializePlatformEarly(); + + InitializeInterceptors(); + + if (!MmapFixedNoReserve(ShadowAddr(), AppAddr() - ShadowAddr())) + Die(); + + tysan_init_is_running = false; + tysan_inited = true; +} + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), + used)) static void (*tysan_init_ptr)() = __tysan_init; +#endif diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h new file mode 100644 index 000000000000..97df28037b0d --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.h @@ -0,0 +1,78 @@ +//===-- tysan.h -------------------------------------------------*- C++ -*-===// +// +// 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 TypeSanitizer. +// +// Private TySan header. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_H +#define TYSAN_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +using __sanitizer::sptr; +using __sanitizer::u16; +using __sanitizer::uptr; + +#include "tysan_platform.h" + +extern "C" { +void tysan_set_type_unknown(const void *addr, uptr size); +void tysan_copy_types(const void *daddr, const void *saddr, uptr size); +} + +namespace __tysan { +extern bool tysan_inited; +extern bool tysan_init_is_running; + +void InitializeInterceptors(); + +enum { TYSAN_MEMBER_TD = 1, TYSAN_STRUCT_TD = 2 }; + +struct tysan_member_type_descriptor { + struct tysan_type_descriptor *Base; + struct tysan_type_descriptor *Access; + uptr Offset; +}; + +struct tysan_struct_type_descriptor { + uptr MemberCount; + struct { + struct tysan_type_descriptor *Type; + uptr Offset; + } Members[1]; // Tail allocated. +}; + +struct tysan_type_descriptor { + uptr Tag; + union { + tysan_member_type_descriptor Member; + tysan_struct_type_descriptor Struct; + }; +}; + +inline tysan_type_descriptor **shadow_for(const void *ptr) { + return (tysan_type_descriptor **)((((uptr)ptr) & AppMask()) * sizeof(ptr) + + ShadowAddr()); +} + +struct Flags { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "tysan_flags.inc" +#undef TYSAN_FLAG + + void SetDefaults(); +}; + +extern Flags flags_data; +inline Flags &flags() { return flags_data; } + +} // namespace __tysan + +#endif // TYSAN_H diff --git a/compiler-rt/lib/tysan/tysan.syms.extra b/compiler-rt/lib/tysan/tysan.syms.extra new file mode 100644 index 000000000000..04e785431619 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.syms.extra @@ -0,0 +1,2 @@ +tysan_* +__tysan_* diff --git a/compiler-rt/lib/tysan/tysan_flags.inc b/compiler-rt/lib/tysan/tysan_flags.inc new file mode 100644 index 000000000000..98b6591f844e --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_flags.inc @@ -0,0 +1,17 @@ +//===-- tysan_flags.inc ---------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// TySan runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef TYSAN_FLAG +#error "Define TYSAN_FLAG prior to including this file!" +#endif + +// TYSAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp new file mode 100644 index 000000000000..08b1010a48ec --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp @@ -0,0 +1,237 @@ +//===-- tysan_interceptors.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 TypeSanitizer. +// +// Interceptors for standard library functions. +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator_dlsym.h" +#include "sanitizer_common/sanitizer_common.h" +#include "tysan/tysan.h" + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#define TYSAN_INTERCEPT___STRDUP 1 +#else +#define TYSAN_INTERCEPT___STRDUP 0 +#endif + +#if SANITIZER_LINUX +extern "C" int mallopt(int param, int value); +#endif + +using namespace __sanitizer; +using namespace __tysan; + +namespace { +struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { + static bool UseImpl() { return !tysan_inited; } +}; +} // namespace + +INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { + if (!tysan_inited && REAL(memset) == nullptr) + return internal_memset(dst, v, size); + + void *res = REAL(memset)(dst, v, size); + tysan_set_type_unknown(dst, size); + return res; +} + +INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memmove) == nullptr) + return internal_memmove(dst, src, size); + + void *res = REAL(memmove)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memcpy) == nullptr) { + // memmove is used here because on some platforms this will also + // intercept the memmove implementation. + return internal_memmove(dst, src, size); + } + + void *res = REAL(memcpy)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF_T offset) { + void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} + +#if !SANITIZER_APPLE +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF64_T offset) { + void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} +#endif + +INTERCEPTOR(char *, strdup, const char *s) { + char *res = REAL(strdup)(s); + if (res) + tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s)); + return res; +} + +#if TYSAN_INTERCEPT___STRDUP +INTERCEPTOR(char *, __strdup, const char *s) { + char *res = REAL(__strdup)(s); + if (res) + tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s)); + return res; +} +#endif // TYSAN_INTERCEPT___STRDUP + +INTERCEPTOR(void *, malloc, uptr size) { + if (DlsymAlloc::Use()) + return DlsymAlloc::Allocate(size); + void *res = REAL(malloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, realloc, void *ptr, uptr size) { + if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Realloc(ptr, size); + void *res = REAL(realloc)(ptr, size); + // We might want to copy the types from the original allocation (although + // that would require that we knew its size). + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) { + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); + void *res = REAL(calloc)(nmemb, size); + if (res) + tysan_set_type_unknown(res, nmemb * size); + return res; +} + +INTERCEPTOR(void, free, void *ptr) { + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + REAL(free)(ptr); +} + +INTERCEPTOR(void *, valloc, uptr size) { + void *res = REAL(valloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +#if SANITIZER_INTERCEPT_MEMALIGN +INTERCEPTOR(void *, memalign, uptr alignment, uptr size) { + void *res = REAL(memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) +#else +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN +#endif // SANITIZER_INTERCEPT_MEMALIGN + +#if SANITIZER_INTERCEPT___LIBC_MEMALIGN +INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { + void *res = REAL(__libc_memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \ + INTERCEPT_FUNCTION(__libc_memalign) +#else +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN +#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN + +#if SANITIZER_INTERCEPT_PVALLOC +INTERCEPTOR(void *, pvalloc, uptr size) { + void *res = REAL(pvalloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) +#else +#define TYSAN_MAYBE_INTERCEPT_PVALLOC +#endif // SANITIZER_INTERCEPT_PVALLOC + +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC +INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) { + void *res = REAL(aligned_alloc)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) +#else +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC +#endif + +INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { + int res = REAL(posix_memalign)(memptr, alignment, size); + if (res == 0 && *memptr) + tysan_set_type_unknown(*memptr, size); + return res; +} + +namespace __tysan { +void InitializeInterceptors() { + static int inited = 0; + CHECK_EQ(inited, 0); + + // Instruct libc malloc to consume less memory. +#if SANITIZER_LINUX + mallopt(1, 0); // M_MXFAST + mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD +#endif + + INTERCEPT_FUNCTION(mmap); + + INTERCEPT_FUNCTION(mmap64); + + INTERCEPT_FUNCTION(strdup); +#if TYSAN_INTERCEPT___STRDUP + INTERCEPT_FUNCTION(__strdup); +#endif + + INTERCEPT_FUNCTION(malloc); + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(free); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(valloc); + TYSAN_MAYBE_INTERCEPT_MEMALIGN; + TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; + TYSAN_MAYBE_INTERCEPT_PVALLOC; + TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC + INTERCEPT_FUNCTION(posix_memalign); + + INTERCEPT_FUNCTION(memset); + INTERCEPT_FUNCTION(memmove); + INTERCEPT_FUNCTION(memcpy); + + inited = 1; +} +} // namespace __tysan diff --git a/compiler-rt/lib/tysan/tysan_platform.h b/compiler-rt/lib/tysan/tysan_platform.h new file mode 100644 index 000000000000..f01392885d93 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_platform.h @@ -0,0 +1,93 @@ +//===------------------------ tysan_platform.h ----------------*- C++ -*-===// +// +// 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 TypeSanitizer. +// +// Platform specific information for TySan. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_PLATFORM_H +#define TYSAN_PLATFORM_H + +namespace __tysan { + +#if defined(__x86_64__) || SANITIZER_APPLE +struct Mapping { + static const uptr kShadowAddr = 0x010000000000ull; + static const uptr kAppAddr = 0x550000000000ull; + static const uptr kAppMemMsk = ~0x780000000000ull; +}; +#elif defined(__aarch64__) +struct Mapping39 { + static const uptr kShadowAddr = 0x0800000000ull; + static const uptr kAppAddr = 0x5500000000ull; + static const uptr kAppMemMsk = ~0x7800000000ull; +}; + +struct Mapping42 { + static const uptr kShadowAddr = 0x10000000000ull; + static const uptr kAppAddr = 0x2aa00000000ull; + static const uptr kAppMemMsk = ~0x3c000000000ull; +}; + +struct Mapping48 { + static const uptr kShadowAddr = 0x0002000000000ull; + static const uptr kAppAddr = 0x0aaaa00000000ull; + static const uptr kAppMemMsk = ~0x0fff800000000ull; +}; +#define TYSAN_RUNTIME_VMA 1 +#else +#error "TySan not supported for this platform!" +#endif + +#if TYSAN_RUNTIME_VMA +extern int vmaSize; +#endif + +enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK }; + +template <typename Mapping, int Type> uptr MappingImpl(void) { + switch (Type) { + case MAPPING_SHADOW_ADDR: + return Mapping::kShadowAddr; + case MAPPING_APP_ADDR: + return Mapping::kAppAddr; + case MAPPING_APP_MASK: + return Mapping::kAppMemMsk; + } +} + +template <int Type> uptr MappingArchImpl(void) { +#if defined(__aarch64__) && !SANITIZER_APPLE + switch (vmaSize) { + case 39: + return MappingImpl<Mapping39, Type>(); + case 42: + return MappingImpl<Mapping42, Type>(); + case 48: + return MappingImpl<Mapping48, Type>(); + } + DCHECK(0); + return 0; +#else + return MappingImpl<Mapping, Type>(); +#endif +} + +ALWAYS_INLINE +uptr ShadowAddr() { return MappingArchImpl<MAPPING_SHADOW_ADDR>(); } + +ALWAYS_INLINE +uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); } + +ALWAYS_INLINE +uptr AppMask() { return MappingArchImpl<MAPPING_APP_MASK>(); } + +} // namespace __tysan + +#endif diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt index 5d45a53d02db..a6c98c40ec77 100644 --- a/compiler-rt/lib/ubsan/CMakeLists.txt +++ b/compiler-rt/lib/ubsan/CMakeLists.txt @@ -43,18 +43,15 @@ include_directories(..) set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_list_if(MSVC /Zl UBSAN_CFLAGS) append_rtti_flag(OFF UBSAN_CFLAGS) -append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CFLAGS) # Too many existing bugs, needs cleanup. append_list_if(COMPILER_RT_HAS_WNO_FORMAT -Wno-format UBSAN_CFLAGS) set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(OFF UBSAN_STANDALONE_CFLAGS) -append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_STANDALONE_CFLAGS) set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) append_rtti_flag(ON UBSAN_CXXFLAGS) -append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS) # Silence warnings in system headers with MSVC. if(NOT CLANG_CL) diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 846cd89ee19f..b1d09a9024e7 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -53,6 +53,7 @@ UBSAN_CHECK(ImplicitSignedIntegerTruncationOrSignChange, UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base") UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent") UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds") +UBSAN_CHECK(LocalOutOfBounds, "local-out-of-bounds", "local-bounds") UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable") UBSAN_CHECK(MissingReturn, "missing-return", "return") UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound") diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index a419cf0b2b55..63319f46734a 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -405,6 +405,28 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, Die(); } +static void handleLocalOutOfBoundsImpl(ReportOptions Opts) { + // FIXME: Pass more diagnostic info. + SymbolizedStackHolder CallerLoc; + CallerLoc.reset(getCallerLocation(Opts.pc)); + Location Loc; + Loc = CallerLoc; + ErrorType ET = ErrorType::LocalOutOfBounds; + ScopedReport R(Opts, Loc, ET); + Diag(Loc, DL_Error, ET, "access out of bounds"); +} + +void __ubsan::__ubsan_handle_local_out_of_bounds() { + GET_REPORT_OPTIONS(false); + handleLocalOutOfBoundsImpl(Opts); +} + +void __ubsan::__ubsan_handle_local_out_of_bounds_abort() { + GET_REPORT_OPTIONS(true); + handleLocalOutOfBoundsImpl(Opts); + Die(); +} + static void handleBuiltinUnreachableImpl(UnreachableData *Data, ReportOptions Opts) { ErrorType ET = ErrorType::UnreachableCall; @@ -877,10 +899,7 @@ static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, namespace __ubsan { -#ifdef UBSAN_CAN_USE_CXXABI - #ifdef _WIN32 - extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, @@ -889,20 +908,17 @@ extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data, } WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default) -#else -SANITIZER_WEAK_ATTRIBUTE -#endif void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, ReportOptions Opts); - #else +SANITIZER_WEAK_ATTRIBUTE void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, ReportOptions Opts) { Die(); } #endif -} // namespace __ubsan +} // namespace __ubsan void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, ValueHandle Value, diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h index 4ffa1439a132..521caa96bc77 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/compiler-rt/lib/ubsan/ubsan_handlers.h @@ -90,6 +90,9 @@ struct OutOfBoundsData { /// \brief Handle an array index out of bounds error. RECOVERABLE(out_of_bounds, OutOfBoundsData *Data, ValueHandle Index) +/// \brief Handle an local object access out of bounds error. +RECOVERABLE(local_out_of_bounds) + struct UnreachableData { SourceLocation Loc; }; diff --git a/compiler-rt/lib/ubsan/ubsan_interface.inc b/compiler-rt/lib/ubsan/ubsan_interface.inc index cb27feb5d7e9..0eb109f37d44 100644 --- a/compiler-rt/lib/ubsan/ubsan_interface.inc +++ b/compiler-rt/lib/ubsan/ubsan_interface.inc @@ -46,6 +46,8 @@ INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1) INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) +INTERFACE_FUNCTION(__ubsan_handle_local_out_of_bounds) +INTERFACE_FUNCTION(__ubsan_handle_local_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow) INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds) diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index 53a3273e4e69..c3ffd41bcacc 100644 --- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -20,12 +20,42 @@ static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; // that "too many errors" has already been reported. static __sanitizer::atomic_uint32_t caller_pcs_sz; -__attribute__((noinline)) static bool report_this_error(uintptr_t caller) { +static char *append_str(const char *s, char *buf, const char *end) { + for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf) + *buf = *p; + return buf; +} + +static char *append_hex(uintptr_t d, char *buf, const char *end) { + // Print the address by nibbles. + for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) { + shift -= 4; + unsigned nibble = (d >> shift) & 0xf; + *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a'; + } + return buf; +} + +static void format_msg(const char *kind, uintptr_t caller, char *buf, + const char *end) { + buf = append_str("ubsan: ", buf, end); + buf = append_str(kind, buf, end); + buf = append_str(" by 0x", buf, end); + buf = append_hex(caller, buf, end); + buf = append_str("\n", buf, end); + if (buf == end) + --buf; // Make sure we don't cause a buffer overflow. + *buf = '\0'; +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind, + uintptr_t caller) { if (caller == 0) - return false; + return; while (true) { unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz); - if (sz > kMaxCallerPcs) return false; // early exit + if (sz > kMaxCallerPcs) + return; // early exit // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg // succeeds in order to not print it multiple times. if (sz > 0 && sz < kMaxCallerPcs) { @@ -33,7 +63,8 @@ __attribute__((noinline)) static bool report_this_error(uintptr_t caller) { for (unsigned i = 0; i < sz; ++i) { p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]); if (p == 0) break; // Concurrent update. - if (p == caller) return false; + if (p == caller) + return; } if (p == 0) continue; // FIXME: yield? } @@ -44,34 +75,27 @@ __attribute__((noinline)) static bool report_this_error(uintptr_t caller) { if (sz == kMaxCallerPcs) { message("ubsan: too many errors\n"); - return false; + return; } __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller); - return true; - } -} -__attribute__((noinline)) static void decorate_msg(char *buf, - uintptr_t caller) { - // print the address by nibbles - for (unsigned shift = sizeof(uintptr_t) * 8; shift;) { - shift -= 4; - unsigned nibble = (caller >> shift) & 0xf; - *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a'; + char msg_buf[128]; + format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); + message(msg_buf); } - // finish the message - buf[0] = '\n'; - buf[1] = '\0'; } #if defined(__ANDROID__) extern "C" __attribute__((weak)) void android_set_abort_message(const char *); -static void abort_with_message(const char *msg) { - if (&android_set_abort_message) android_set_abort_message(msg); +static void abort_with_message(const char *kind, uintptr_t caller) { + char msg_buf[128]; + format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); + if (&android_set_abort_message) + android_set_abort_message(msg_buf); abort(); } #else -static void abort_with_message(const char *) { abort(); } +static void abort_with_message(const char *kind, uintptr_t caller) { abort(); } #endif #if SANITIZER_DEBUG @@ -89,33 +113,21 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { #define INTERFACE extern "C" __attribute__((visibility("default"))) -// How many chars we need to reserve to print an address. -constexpr unsigned kAddrBuf = SANITIZER_WORDSIZE / 4; -#define MSG_TMPL(msg) "ubsan: " msg " by 0x" -#define MSG_TMPL_END(buf, msg) (buf + sizeof(MSG_TMPL(msg)) - 1) -// Reserve an additional byte for '\n'. -#define MSG_BUF_LEN(msg) (sizeof(MSG_TMPL(msg)) + kAddrBuf + 1) - -#define HANDLER_RECOVER(name, msg) \ - INTERFACE void __ubsan_handle_##name##_minimal() { \ - uintptr_t caller = GET_CALLER_PC(); \ - if (!report_this_error(caller)) return; \ - char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \ - decorate_msg(MSG_TMPL_END(msg_buf, msg), caller); \ - message(msg_buf); \ +#define HANDLER_RECOVER(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal() { \ + __ubsan_report_error(kind, GET_CALLER_PC()); \ } -#define HANDLER_NORECOVER(name, msg) \ - INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ - char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \ - decorate_msg(MSG_TMPL_END(msg_buf, msg), GET_CALLER_PC()); \ - message(msg_buf); \ - abort_with_message(msg_buf); \ +#define HANDLER_NORECOVER(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ + uintptr_t caller = GET_CALLER_PC(); \ + __ubsan_report_error(kind, caller); \ + abort_with_message(kind, caller); \ } -#define HANDLER(name, msg) \ - HANDLER_RECOVER(name, msg) \ - HANDLER_NORECOVER(name, msg) +#define HANDLER(name, kind) \ + HANDLER_RECOVER(name, kind) \ + HANDLER_NORECOVER(name, kind) HANDLER(type_mismatch, "type-mismatch") HANDLER(alignment_assumption, "alignment-assumption") @@ -126,6 +138,7 @@ HANDLER(negate_overflow, "negate-overflow") HANDLER(divrem_overflow, "divrem-overflow") HANDLER(shift_out_of_bounds, "shift-out-of-bounds") HANDLER(out_of_bounds, "out-of-bounds") +HANDLER(local_out_of_bounds, "local-out-of-bounds") HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable") HANDLER_RECOVER(missing_return, "missing-return") HANDLER(vla_bound_not_positive, "vla-bound-not-positive") diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt index 7e3f1a0aa616..e7f01a2f4f16 100644 --- a/compiler-rt/lib/xray/CMakeLists.txt +++ b/compiler-rt/lib/xray/CMakeLists.txt @@ -96,6 +96,16 @@ set(hexagon_SOURCES xray_trampoline_hexagon.S ) +set(riscv32_SOURCES + xray_riscv.cpp + xray_trampoline_riscv32.S + ) + +set(riscv64_SOURCES + xray_riscv.cpp + xray_trampoline_riscv64.S + ) + set(XRAY_SOURCE_ARCHS arm armhf @@ -156,6 +166,8 @@ set(XRAY_ALL_SOURCE_FILES ${mips64_SOURCES} ${mips64el_SOURCES} ${powerpc64le_SOURCES} + ${riscv32_SOURCES} + ${riscv64_SOURCES} ${XRAY_IMPL_HEADERS} ) list(REMOVE_DUPLICATES XRAY_ALL_SOURCE_FILES) diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp index b6f0e6762f16..4ec492c266d8 100644 --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -57,6 +57,10 @@ static const int16_t cSledLength = 64; static const int16_t cSledLength = 8; #elif defined(__hexagon__) static const int16_t cSledLength = 20; +#elif defined(__riscv) && (__riscv_xlen == 64) +static const int16_t cSledLength = 68; +#elif defined(__riscv) && (__riscv_xlen == 32) +static const int16_t cSledLength = 52; #else #error "Unsupported CPU Architecture" #endif /* CPU architecture */ diff --git a/compiler-rt/lib/xray/xray_riscv.cpp b/compiler-rt/lib/xray/xray_riscv.cpp new file mode 100644 index 000000000000..e3a7cdb18b64 --- /dev/null +++ b/compiler-rt/lib/xray/xray_riscv.cpp @@ -0,0 +1,266 @@ +//===-- xray_riscv.cpp ----------------------------------------*- C++ -*-===// +// +// 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 XRay, a dynamic runtime instrumentation system. +// +// Implementation of RISC-V specific routines (32- and 64-bit). +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_common.h" +#include "xray_defs.h" +#include "xray_interface_internal.h" +#include <atomic> + +namespace __xray { + +// The machine codes for some instructions used in runtime patching. +enum PatchOpcodes : uint32_t { + PO_ADDI = 0x00000013, // addi rd, rs1, imm + PO_ADD = 0x00000033, // add rd, rs1, rs2 + PO_SW = 0x00002023, // sw rs2, imm(rs1) + PO_SD = 0x00003023, // sd rs2, imm(rs1) + PO_LUI = 0x00000037, // lui rd, imm + PO_OR = 0x00006033, // or rd, rs1, rs2 + PO_SLLI = 0x00001013, // slli rd, rs1, shamt + PO_JALR = 0x00000067, // jalr rd, rs1 + PO_LW = 0x00002003, // lw rd, imm(rs1) + PO_LD = 0x00003003, // ld rd, imm(rs1) + PO_J = 0x0000006f, // jal imm + PO_NOP = PO_ADDI, // addi x0, x0, 0 +}; + +enum RegNum : uint32_t { + RN_X0 = 0, + RN_RA = 1, + RN_SP = 2, + RN_T1 = 6, + RN_A0 = 10, +}; + +static inline uint32_t encodeRTypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rs2, uint32_t Rd) { + return Rs2 << 20 | Rs1 << 15 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeITypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rd, uint32_t Imm) { + return Imm << 20 | Rs1 << 15 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeSTypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rs2, uint32_t Imm) { + uint32_t ImmMSB = (Imm & 0xfe0) << 20; + uint32_t ImmLSB = (Imm & 0x01f) << 7; + return ImmMSB | Rs2 << 20 | Rs1 << 15 | ImmLSB | Opcode; +} + +static inline uint32_t encodeUTypeInstruction(uint32_t Opcode, uint32_t Rd, + uint32_t Imm) { + return Imm << 12 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeJTypeInstruction(uint32_t Opcode, uint32_t Rd, + uint32_t Imm) { + uint32_t ImmMSB = (Imm & 0x100000) << 11; + uint32_t ImmLSB = (Imm & 0x7fe) << 20; + uint32_t Imm11 = (Imm & 0x800) << 9; + uint32_t Imm1912 = (Imm & 0xff000); + return ImmMSB | ImmLSB | Imm11 | Imm1912 | Rd << 7 | Opcode; +} + +static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } +static uint32_t lo12(uint32_t val) { return val & 0xfff; } + +static inline bool patchSled(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + void (*TracingHook)()) XRAY_NEVER_INSTRUMENT { + // When |Enable| == true, + // We replace the following compile-time stub (sled): + // + // xray_sled_n: + // J .tmpN + // 21 or 33 C.NOPs (42 or 66 bytes) + // .tmpN + // + // With one of the following runtime patches: + // + // xray_sled_n (32-bit): + // addi sp, sp, -16 ;create stack frame + // sw ra, 12(sp) ;save return address + // sw a0, 8(sp) ;save register a0 + // lui ra, %hi(__xray_FunctionEntry/Exit) + // addi ra, ra, %lo(__xray_FunctionEntry/Exit) + // lui a0, %hi(function_id) + // addi a0, a0, %lo(function_id) ;pass function id + // jalr ra ;call Tracing hook + // lw a0, 8(sp) ;restore register a0 + // lw ra, 12(sp) ;restore return address + // addi sp, sp, 16 ;delete stack frame + // + // xray_sled_n (64-bit): + // addi sp, sp, -32 ;create stack frame + // sd ra, 24(sp) ;save return address + // sd a0, 16(sp) ;save register a0 + // sd t1, 8(sp) ;save register t1 + // lui t1, %highest(__xray_FunctionEntry/Exit) + // addi t1, t1, %higher(__xray_FunctionEntry/Exit) + // slli t1, t1, 32 + // lui ra, ra, %hi(__xray_FunctionEntry/Exit) + // addi ra, ra, %lo(__xray_FunctionEntry/Exit) + // add ra, t1, ra + // lui a0, %hi(function_id) + // addi a0, a0, %lo(function_id) ;pass function id + // jalr ra ;call Tracing hook + // ld t1, 8(sp) ;restore register t1 + // ld a0, 16(sp) ;restore register a0 + // ld ra, 24(sp) ;restore return address + // addi sp, sp, 32 ;delete stack frame + // + // Replacement of the first 4-byte instruction should be the last and atomic + // operation, so that the user code which reaches the sled concurrently + // either jumps over the whole sled, or executes the whole sled when the + // latter is ready. + // + // When |Enable|==false, we set back the first instruction in the sled to be + // J 44 bytes (rv32) + // J 68 bytes (rv64) + + uint32_t *Address = reinterpret_cast<uint32_t *>(Sled.address()); + if (Enable) { +#if __riscv_xlen == 64 + // If the ISA is RV64, the Tracing Hook needs to be typecast to a 64 bit + // value. + uint32_t LoTracingHookAddr = lo12(reinterpret_cast<uint64_t>(TracingHook)); + uint32_t HiTracingHookAddr = hi20(reinterpret_cast<uint64_t>(TracingHook)); + uint32_t HigherTracingHookAddr = + lo12((reinterpret_cast<uint64_t>(TracingHook) + 0x80000000) >> 32); + uint32_t HighestTracingHookAddr = + hi20((reinterpret_cast<uint64_t>(TracingHook) + 0x80000000) >> 32); +#elif __riscv_xlen == 32 + // We typecast the Tracing Hook to a 32 bit value for RV32 + uint32_t LoTracingHookAddr = lo12(reinterpret_cast<uint32_t>(TracingHook)); + uint32_t HiTracingHookAddr = hi20((reinterpret_cast<uint32_t>(TracingHook)); +#endif + uint32_t LoFunctionID = lo12(FuncId); + uint32_t HiFunctionID = hi20(FuncId); + + // The sled that is patched in for RISCV64 defined below. We need the entire + // sleds corresponding to both ISAs to be protected by defines because the + // first few instructions are all different, because we store doubles in + // case of RV64 and store words for RV32. Subsequently, we have LUI - and in + // case of RV64, we need extra instructions from this point on, so we see + // differences in addresses to which instructions are stored. + size_t Idx = 1U; + const uint32_t XLenBytes = __riscv_xlen / 8; +#if __riscv_xlen == 64 + const uint32_t LoadOp = PatchOpcodes::PO_LD; + const uint32_t StoreOp = PatchOpcodes::PO_SD; +#elif __riscv_xlen == 32 + const uint32_t LoadOp = PatchOpcodes::PO_LW; + const uint32_t StoreOp = PatchOpcodes::PO_SW; +#endif + + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_RA, 3 * XLenBytes); + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_A0, 2 * XLenBytes); + +#if __riscv_xlen == 64 + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_T1, XLenBytes); + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_T1, + HighestTracingHookAddr); + Address[Idx++] = + encodeITypeInstruction(PatchOpcodes::PO_ADDI, RegNum::RN_T1, + RegNum::RN_T1, HigherTracingHookAddr); + Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_SLLI, + RegNum::RN_T1, RegNum::RN_T1, 32); +#endif + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_RA, + HiTracingHookAddr); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_RA, RegNum::RN_RA, LoTracingHookAddr); +#if __riscv_xlen == 64 + Address[Idx++] = encodeRTypeInstruction(PatchOpcodes::PO_ADD, RegNum::RN_RA, + RegNum::RN_T1, RegNum::RN_RA); +#endif + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_A0, + HiFunctionID); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_A0, RegNum::RN_A0, LoFunctionID); + Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_JALR, + RegNum::RN_RA, RegNum::RN_RA, 0); + +#if __riscv_xlen == 64 + Address[Idx++] = + encodeITypeInstruction(LoadOp, RegNum::RN_SP, RegNum::RN_T1, XLenBytes); +#endif + Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP, + RegNum::RN_A0, 2 * XLenBytes); + Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP, + RegNum::RN_RA, 3 * XLenBytes); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, 4 * XLenBytes); + + uint32_t CreateStackSpace = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, -4 * XLenBytes); + + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint32_t> *>(Address), CreateStackSpace, + std::memory_order_release); + } else { + uint32_t CreateBranch = encodeJTypeInstruction( + // Jump distance is different in both ISAs due to difference in size of + // sleds +#if __riscv_xlen == 64 + PatchOpcodes::PO_J, RegNum::RN_X0, + 68); // jump encodes an offset of 68 +#elif __riscv_xlen == 32 + PatchOpcodes::PO_J, RegNum::RN_X0, + 44); // jump encodes an offset of 44 +#endif + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint32_t> *>(Address), CreateBranch, + std::memory_order_release); + } + return true; +} + +bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + // We don't support logging argument at this moment, so we always + // use EntryTrampoline. + return patchSled(Enable, FuncId, Sled, Trampolines.EntryTrampoline); +} + +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); +} + +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline); +} + +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return false; +} + +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return false; +} +} // namespace __xray + +extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {} diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv32.S b/compiler-rt/lib/xray/xray_trampoline_riscv32.S new file mode 100644 index 000000000000..05e3d61e5ef7 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv32.S @@ -0,0 +1,89 @@ +//===-- xray_trampoline_riscv32.s ----------------------------------*- ASM -*-===// +// +// 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 XRay, a dynamic runtime instrumentation system. +// +// This implements the riscv32-specific assembler for the trampolines. +// +//===----------------------------------------------------------------------===// + +#include "../sanitizer_common/sanitizer_asm.h" + +.macro SAVE_ARG_REGISTERS + // Push argument registers to stack + addi sp, sp, -112 + CFI_DEF_CFA_OFFSET(112) + sw ra, 108(sp) + sw a7, 104(sp) + sw a6, 100(sp) + sw a5, 96(sp) + sw a4, 92(sp) + sw a3, 88(sp) + sw a2, 84(sp) + sw a1, 80(sp) + sw a0, 76(sp) + fsd fa7, 64(sp) + fsd fa6, 56(sp) + fsd fa5, 48(sp) + fsd fa4, 40(sp) + fsd fa3, 32(sp) + fsd fa2, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro RESTORE_ARG_REGISTERS + // Restore argument registers + fld fa0, 8(sp) + fld fa1, 16(sp) + fld fa2, 24(sp) + fld fa3, 32(sp) + fld fa4, 40(sp) + fld fa5, 48(sp) + fld fa6, 56(sp) + fld fa7, 64(sp) + lw a0, 76(sp) + lw a1, 80(sp) + lw a2, 84(sp) + lw a3, 88(sp) + lw a4, 92(sp) + lw a5, 96(sp) + lw a6, 100(sp) + lw a7, 104(sp) + lw ra, 108(sp) + addi sp, sp, 112 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro SAVE_RET_REGISTERS + // Push return registers to stack + addi sp, sp, -32 + CFI_DEF_CFA_OFFSET(32) + sw ra, 28(sp) + sw a1, 24(sp) + sw a0, 20(sp) + fsd fa1, 8(sp) + fsd fa0, 0(sp) +.endm + +.macro RESTORE_RET_REGISTERS + // Restore return registers + fld fa0, 0(sp) + fld fa1, 8(sp) + lw a0, 20(sp) + lw a1, 24(sp) + lw ra, 28(sp) + addi sp, sp, 32 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro LOAD_XLEN, rd, src + lw \rd, \src +.endm + +#include "xray_trampoline_riscv_common.S" diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv64.S b/compiler-rt/lib/xray/xray_trampoline_riscv64.S new file mode 100644 index 000000000000..692350eaaa38 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv64.S @@ -0,0 +1,89 @@ +//===-- xray_trampoline_riscv64.s ----------------------------------*- ASM -*-===// +// +// 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 XRay, a dynamic runtime instrumentation system. +// +// This implements the riscv64-specific assembler for the trampolines. +// +//===----------------------------------------------------------------------===// + +#include "../sanitizer_common/sanitizer_asm.h" + +.macro SAVE_ARG_REGISTERS + // Push return registers to stack + addi sp, sp, -144 + CFI_DEF_CFA_OFFSET(144) + sd ra, 136(sp) + sd a7, 128(sp) + sd a6, 120(sp) + sd a5, 112(sp) + sd a4, 104(sp) + sd a3, 96(sp) + sd a2, 88(sp) + sd a1, 80(sp) + sd a0, 72(sp) + fsd fa7, 64(sp) + fsd fa6, 56(sp) + fsd fa5, 48(sp) + fsd fa4, 40(sp) + fsd fa3, 32(sp) + fsd fa2, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro SAVE_RET_REGISTERS + // Push return registers to stack + addi sp, sp, -48 + CFI_DEF_CFA_OFFSET(48) + sd ra, 40(sp) + sd a1, 32(sp) + sd a0, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro RESTORE_RET_REGISTERS + // Restore return registers + fld fa0, 8(sp) + fld fa1, 16(sp) + ld a0, 24(sp) + ld a1, 32(sp) + ld ra, 40(sp) + addi sp, sp, 48 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro RESTORE_ARG_REGISTERS + // Restore argument registers + fld fa0, 8(sp) + fld fa1, 16(sp) + fld fa2, 24(sp) + fld fa3, 32(sp) + fld fa4, 40(sp) + fld fa5, 48(sp) + fld fa6, 56(sp) + fld fa7, 64(sp) + ld a0, 72(sp) + ld a1, 80(sp) + ld a2, 88(sp) + ld a3, 96(sp) + ld a4, 104(sp) + ld a5, 112(sp) + ld a6, 120(sp) + ld a7, 128(sp) + ld ra, 136(sp) + addi sp, sp, 144 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro LOAD_XLEN, rd, src + ld \rd, \src +.endm + +#include "xray_trampoline_riscv_common.S" diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv_common.S b/compiler-rt/lib/xray/xray_trampoline_riscv_common.S new file mode 100644 index 000000000000..746d612e9820 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv_common.S @@ -0,0 +1,96 @@ +//===-- xray_trampoline_riscv_common.s --------------------------*- ASM -*-===// +// +// 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 XRay, a dynamic runtime instrumentation system. +// +// This implements the trampolines code shared between riscv32 and riscv64. +// +//===----------------------------------------------------------------------===// + +#include "../builtins/assembly.h" + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionEntry) + ASM_TYPE_FUNCTION(__xray_FunctionEntry) +ASM_SYMBOL(__xray_FunctionEntry): + CFI_STARTPROC + SAVE_ARG_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 0 means we are tracing an entry event + li a1, 0 + jalr a2 + +1: + RESTORE_ARG_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionEntry) + CFI_ENDPROC + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionExit) + ASM_TYPE_FUNCTION(__xray_FunctionExit) +ASM_SYMBOL(__xray_FunctionExit): + CFI_STARTPROC + SAVE_RET_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 1 means we are tracing an exit event + li a1, 1 + jalr a2 + +1: + RESTORE_RET_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionExit) + CFI_ENDPROC + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionTailExit) + ASM_TYPE_FUNCTION(__xray_FunctionTailExit) +ASM_SYMBOL(__xray_FunctionTailExit): + CFI_STARTPROC + SAVE_ARG_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 2 means we are tracing a tail exit event + li a1, 2 + jalr a2 + +1: + RESTORE_ARG_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionTailExit) + CFI_ENDPROC diff --git a/compiler-rt/lib/xray/xray_tsc.h b/compiler-rt/lib/xray/xray_tsc.h index e1cafe1bf11d..b62a686d6ce0 100644 --- a/compiler-rt/lib/xray/xray_tsc.h +++ b/compiler-rt/lib/xray/xray_tsc.h @@ -43,7 +43,7 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { #elif defined(__powerpc64__) #include "xray_powerpc64.inc" #elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ - defined(__hexagon__) || defined(__loongarch_lp64) + defined(__hexagon__) || defined(__loongarch_lp64) || defined(__riscv) // Emulated TSC. // There is no instruction like RDTSCP in user mode on ARM. ARM's CP15 does // not have a constant frequency like TSC on x86(_64), it may go faster diff --git a/compiler-rt/test/asan/TestCases/Linux/global-overflow-bfd.cpp b/compiler-rt/test/asan/TestCases/Linux/global-overflow-bfd.cpp index bf82a517df37..67331606c3ba 100644 --- a/compiler-rt/test/asan/TestCases/Linux/global-overflow-bfd.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/global-overflow-bfd.cpp @@ -2,6 +2,9 @@ // false negatives with the BFD linker. // RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// Android does not use bfd. +// UNSUPPORTED: android + #include <string.h> int main(int argc, char **argv) { static char XXX[10]; diff --git a/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp b/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp index 2d729497548d..60ef0e5b0de6 100644 --- a/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp @@ -23,6 +23,8 @@ // RUN: | grep -v "__sanitizer_weak_hook" \ // RUN: | grep -v "__sanitizer_override_function" \ // RUN: | grep -v "__sanitizer_override_function_by_addr" \ +// RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss" \ +// RUN: | grep -v "__ubsan_handle_dynamic_type_cache_miss_abort" \ // RUN: | grep -v "__sanitizer_register_weak_function" \ // RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports // diff --git a/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp b/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp new file mode 100644 index 000000000000..90db0d45af2d --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp @@ -0,0 +1,34 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ABORT +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RETURN-NULL + +// RUN: %clangxx_asan -O0 %s -o %t -DUSER_FUNCTION +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RETURN-NULL + +#if USER_FUNCTION +// On Windows, flags configured through the user-defined function `__asan_default_options` +// are suspected to not always be honored according to GitHub bug: +// https://github.com/llvm/llvm-project/issues/117925 +// This test ensures we do not regress on `allocator_may_return_null` specifically. +extern "C" __declspec(dllexport) extern const char *__asan_default_options() { + return "allocator_may_return_null=1"; +} +#endif + +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <limits> + +int main() { + // Attempt to allocate an excessive amount of memory, which should + // terminate the program unless `allocator_may_return_null` is set. + size_t max = std::numeric_limits<size_t>::max(); + + // CHECK-ABORT: exceeds maximum supported size + // CHECK-ABORT: ABORT + free(malloc(max)); + + printf("Success"); // CHECK-RETURN-NULL: Success + return 0; +} diff --git a/compiler-rt/test/builtins/Unit/divdf3_test.c b/compiler-rt/test/builtins/Unit/divdf3_test.c index 1b8f2b398a91..f1f3f3b4f7e0 100644 --- a/compiler-rt/test/builtins/Unit/divdf3_test.c +++ b/compiler-rt/test/builtins/Unit/divdf3_test.c @@ -113,5 +113,9 @@ int main() if (test__divdf3(0x1.0p-1022, 0x1.0028p+52, UINT64_C(0x1))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1) + if (test__divdf3(1.0, 0x1.fffffffffffffp-1, UINT64_C(0x3ff0000000000001))) + return 1; + return 0; } diff --git a/compiler-rt/test/builtins/Unit/divsf3_test.c b/compiler-rt/test/builtins/Unit/divsf3_test.c index 7a783cdfb863..f8cb6169ac28 100644 --- a/compiler-rt/test/builtins/Unit/divsf3_test.c +++ b/compiler-rt/test/builtins/Unit/divsf3_test.c @@ -107,5 +107,9 @@ int main() if (test__divsf3(0x1.fffffep-126F, 2.F, UINT32_C(0x00800000))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1) + if (test__divsf3(1.0F, 0x1.fffffep-1F, UINT32_C(0x3f800001))) + return 1; + return 0; } diff --git a/compiler-rt/test/builtins/Unit/divtf3_test.c b/compiler-rt/test/builtins/Unit/divtf3_test.c index d46fcc047769..3c70e43741af 100644 --- a/compiler-rt/test/builtins/Unit/divtf3_test.c +++ b/compiler-rt/test/builtins/Unit/divtf3_test.c @@ -156,6 +156,11 @@ int main() { UINT64_C(0x0001000000000000), UINT64_C(0))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1). + if (test__divtf3(1.0L, TF_C(0x1.ffffffffffffffffffffffffffffp-1), + UINT64_C(0x3FFF000000000000), UINT64_C(1))) + return 1; + #else printf("skipped\n"); diff --git a/compiler-rt/test/builtins/Unit/truncxfhf2_test.c b/compiler-rt/test/builtins/Unit/truncxfhf2_test.c new file mode 100644 index 000000000000..b5e2a91f0b93 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/truncxfhf2_test.c @@ -0,0 +1,74 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_truncxfhf2 + +#include <stdio.h> + +#include "fp_test.h" + +#if HAS_80_BIT_LONG_DOUBLE + +TYPE_FP16 __truncxfhf2(xf_float f); + +int test_truncxfhf2(uint16_t inputHi, uint64_t inputLo, uint16_t e) { + xf_float a = F80FromRep80(inputHi, inputLo); + TYPE_FP16 x = __truncxfhf2(a); + int ret = compareResultH(x, e); + if (ret) { + printf("error in test__truncxfhf2(%Lf) = %#.4x, " + "expected %#.4x\n", + a, toRep16(x), e); + } + return ret; +} + +int main() { + // Small positive value + if (test_truncxfhf2(UINT16_C(0x3ffb), UINT64_C(0xccc0000000000000), + UINT16_C(0x2e66))) + return 1; + + // Small negative value + if (test_truncxfhf2(UINT16_C(0xbffb), UINT64_C(0xccc0000000000000), + UINT16_C(0xae66))) + return 1; + + // Zero + if (test_truncxfhf2(UINT16_C(0x0), UINT64_C(0x0), UINT16_C(0))) + return 1; + + // Smallest positive non-zero value + if (test_truncxfhf2(UINT16_C(0x3fef), UINT64_C(0x8000000000000000), + UINT16_C(0x0100))) + return 1; + + // Smallest negative non-zero value + if (test_truncxfhf2(UINT16_C(0xbfef), UINT64_C(0x8000000000000000), + UINT16_C(0x8100))) + return 1; + + // Positive infinity + if (test_truncxfhf2(UINT16_C(0x7fff), UINT64_C(0x8000000000000000), + UINT16_C(0x7c00))) + return 1; + + // Negative infinity + if (test_truncxfhf2(UINT16_C(0xffff), UINT64_C(0x8000000000000000), + UINT16_C(0xfc00))) + return 1; + + // NaN + if (test_truncxfhf2(UINT16_C(0x7fff), UINT64_C(0xc000000000000000), + UINT16_C(0x7e00))) + return 1; + + return 0; +} + +#else + +int main() { + printf("skipped\n"); + return 0; +} + +#endif diff --git a/compiler-rt/test/fuzzer/noasan-strcmp.test b/compiler-rt/test/fuzzer/noasan-strcmp.test index 0d82d6b2846f..f73af35f5d89 100644 --- a/compiler-rt/test/fuzzer/noasan-strcmp.test +++ b/compiler-rt/test/fuzzer/noasan-strcmp.test @@ -1,4 +1,4 @@ -UNSUPPORTED: darwin, target={{.*(freebsd|windows).*}} +UNSUPPORTED: darwin, target={{.*(freebsd|windows).*}}, target=aarch64{{.*}} RUN: %cpp_compiler -fno-sanitize=address %S/StrcmpTest.cpp -o %t-NoAsanStrcmpTest RUN: not %run %t-NoAsanStrcmpTest -seed=1 -runs=2000000 2>&1 | FileCheck %s diff --git a/compiler-rt/test/memprof/TestCases/default_options.cpp b/compiler-rt/test/memprof/TestCases/default_options.cpp index 1b6b61fc048b..4042a7df588b 100644 --- a/compiler-rt/test/memprof/TestCases/default_options.cpp +++ b/compiler-rt/test/memprof/TestCases/default_options.cpp @@ -1,5 +1,8 @@ // RUN: %clangxx_memprof -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// Check that overriding __memprof_default_options() takes precedence over the LLVM flag +// RUN: %clangxx_memprof -O2 %s -o %t-flag -mllvm -memprof-runtime-default-options="verbosity=0 help=0" && %run %t-flag 2>&1 | FileCheck %s + const char *kMemProfDefaultOptions = "verbosity=1 help=1"; extern "C" const char *__memprof_default_options() { diff --git a/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp b/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp new file mode 100644 index 000000000000..426849d1cea0 --- /dev/null +++ b/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp @@ -0,0 +1,16 @@ +// RUN: %clangxx_memprof %s -o %t + +// RUN: %env_memprof_opts=print_text=true:log_path=stdout:dump_at_exit=false %run %t | count 0 +// RUN: %env_memprof_opts=print_text=true:log_path=stdout:dump_at_exit=true %run %t | FileCheck %s + +#include <stdlib.h> +#include <string.h> + +int main() { + char *x = (char *)malloc(10); + memset(x, 0, 10); + free(x); + return 0; +} + +// CHECK: Recorded MIBs diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp new file mode 100644 index 000000000000..dddcfcf98c5c --- /dev/null +++ b/compiler-rt/test/memprof/TestCases/set_options.cpp @@ -0,0 +1,16 @@ +// RUN: %clangxx_memprof %s -o %t-default +// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT + +// RUN: %clangxx_memprof %s -mllvm -memprof-runtime-default-options="print_text=true,log_path=stdout,atexit=false" -o %t +// RUN: %run %t | FileCheck %s + +#include <sanitizer/memprof_interface.h> +#include <stdio.h> + +int main() { + printf("Options: \"%s\"\n", __memprof_default_options()); + return 0; +} + +// DEFAULT: Options: "" +// CHECK: Options: "print_text=true,log_path=stdout,atexit=false" diff --git a/compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll b/compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll new file mode 100644 index 000000000000..2d6b33933755 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll @@ -0,0 +1,4 @@ +define i32 @foo() { +entry: + ret i32 42 +} diff --git a/compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll b/compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll new file mode 100644 index 000000000000..ee479a1ffa4f --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll @@ -0,0 +1 @@ +@x = global i32 42 diff --git a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll new file mode 100644 index 000000000000..5a8dbfc532b0 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll @@ -0,0 +1,30 @@ +; Check that files passed with the -lazy option aren't linked unless they're +; needed. The foo-ret-42.ll file, which contains only code, should not be +; needed in this -noexec case, whereas x.o, which contains a global variable +; referenced by main, should be linked (despite being passed with -lazy). +; +; RUN: rm -rf %t && mkdir -p %t +; RUN: %clang -c -o %t/foo.o %S/Inputs/foo-ret-42.ll +; RUN: %clang -c -o %t/x.o %S/Inputs/var-x-42.ll +; RUN: %clang -c -o %t/main.o %s +; RUN: %llvm_jitlink -noexec -show-linked-files %t/main.o -lazy %t/foo.o \ +; RUN: -lazy %t/x.o | FileCheck %s +; +; UNSUPPORTED: system-windows +; REQUIRES: target={{(arm|aarch|x86_)64.*}} +; +; CHECK: Linking {{.*}}main.o +; CHECK-DAG: Linking <indirect stubs graph #1> +; CHECK-DAG: Linking {{.*}}x.o +; CHECK-NOT: Linking {{.*}}foo.o + +declare i32 @foo() +@x = external global i32 + +define i32 @main(i32 %argc, ptr %argv) { +entry: + %foo_result = call i32 @foo() + %x_val = load i32, ptr @x + %result = add nsw i32 %foo_result, %x_val + ret i32 %result +} diff --git a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test b/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test deleted file mode 100644 index 951688d7961d..000000000000 --- a/compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test +++ /dev/null @@ -1,6 +0,0 @@ -// Test that the orc-remote-executor tool errors out as expected when called -// with no arguments. -// -// RUN: not %orc_rt_executor 2>&1 | FileCheck %s - -// CHECK: usage: orc-rt-executor [help] [<mode>] <program arguments>... diff --git a/compiler-rt/test/orc/lit.cfg.py b/compiler-rt/test/orc/lit.cfg.py index 6dfa94b11cc9..7a6eb4e7de32 100644 --- a/compiler-rt/test/orc/lit.cfg.py +++ b/compiler-rt/test/orc/lit.cfg.py @@ -16,6 +16,11 @@ if config.host_arch == "x86_64h" and config.target_arch == "x86_64": host_arch_compatible = True if host_arch_compatible: config.available_features.add("host-arch-compatible") + +# If the target OS hasn't been set then assume host. +if not config.target_os: + config.target_os = config.host_os + config.test_target_is_host_executable = ( config.target_os == config.host_os and host_arch_compatible ) diff --git a/compiler-rt/test/profile/ContinuousSyncMode/basic.c b/compiler-rt/test/profile/ContinuousSyncMode/basic.c index e8bd087a0f59..531877b78a1a 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/basic.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/basic.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: %clang_profgen_cont -fcoverage-mapping -o %t.exe %s // RUN: echo "garbage" > %t.profraw diff --git a/compiler-rt/test/profile/ContinuousSyncMode/get-filename.c b/compiler-rt/test/profile/ContinuousSyncMode/get-filename.c index 40a0cc5ffd68..e341dd429eb8 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/get-filename.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/get-filename.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: %clang_pgogen_cont -o %t.exe %s // RUN: env LLVM_PROFILE_FILE="%c%t.profraw" %run %t.exe %t.profraw diff --git a/compiler-rt/test/profile/ContinuousSyncMode/image-with-mcdc.c b/compiler-rt/test/profile/ContinuousSyncMode/image-with-mcdc.c index d171badbf4d3..fa24e26c4c53 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/image-with-mcdc.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/image-with-mcdc.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: %clang_profgen_cont -fcoverage-mapping -fcoverage-mcdc -O3 -o %t.exe %s // RUN: env LLVM_PROFILE_FILE="%c%t.profraw" %run %t.exe 3 3 diff --git a/compiler-rt/test/profile/ContinuousSyncMode/multi-threaded.cpp b/compiler-rt/test/profile/ContinuousSyncMode/multi-threaded.cpp index ff05a69a5e7d..aa0a46e0fc39 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/multi-threaded.cpp +++ b/compiler-rt/test/profile/ContinuousSyncMode/multi-threaded.cpp @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: rm -f %t.profraw // RUN: %clangxx_pgogen_cont -lpthread %s -o %t.exe -mllvm -disable-vp -fprofile-update=atomic diff --git a/compiler-rt/test/profile/ContinuousSyncMode/online-merging.c b/compiler-rt/test/profile/ContinuousSyncMode/online-merging.c index 54346487a5c7..c1931410f8c7 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/online-merging.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/online-merging.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // Test the online merging mode (%m) along with continuous mode (%c). // diff --git a/compiler-rt/test/profile/ContinuousSyncMode/pid-substitution.c b/compiler-rt/test/profile/ContinuousSyncMode/pid-substitution.c index 309b685a95c5..8a00b28825ca 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/pid-substitution.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/pid-substitution.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: rm -rf %t.dir && mkdir -p %t.dir // RUN: %clang_pgogen_cont -o %t.exe %s diff --git a/compiler-rt/test/profile/ContinuousSyncMode/set-filename.c b/compiler-rt/test/profile/ContinuousSyncMode/set-filename.c index 106e12e4e3b6..abc72646d16b 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/set-filename.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/set-filename.c @@ -1,4 +1,4 @@ -// REQUIRES: target={{.*(darwin|aix).*}} +// REQUIRES: continuous-mode // RUN: %clang_pgogen_cont -o %t.exe %s // RUN: env LLVM_PROFILE_FILE="%c%t.profraw" %run %t.exe %t.profraw %t.bad diff --git a/compiler-rt/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov b/compiler-rt/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov index aa202763fd56..233fd142444a 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-gcov-exceptions.gcno // CHECK-NEXT: -: 0:Data:instrprof-gcov-exceptions.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: -: 1:#include <string> // CHECK-NEXT: -: 2: // CHECK-NEXT: 1: 3:void asd(std::string i) { diff --git a/compiler-rt/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov index 9297073d21ef..a25632d475b3 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-gcov-multiple-bbs-single-line.gcno // CHECK-NEXT: -: 0:Data:instrprof-gcov-multiple-bbs-single-line.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT:function main called 1 returned 100% blocks executed 77% // CHECK-NEXT: 1: 1:int main(void) // CHECK-NEXT: -: 2:{ diff --git a/compiler-rt/test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov index 5a570a04742d..4dc68177e0b7 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-gcov-one-line-function.gcno // CHECK-NEXT: -: 0:Data:instrprof-gcov-one-line-function.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: 1: 1:void foo() { } // CHECK-NEXT: -: 2: // CHECK-NEXT: 1: 3:void bar() { } diff --git a/compiler-rt/test/profile/Inputs/instrprof-gcov-switch1.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-gcov-switch1.c.gcov index 741dff59954b..2b4d67f9abbe 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-gcov-switch1.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-gcov-switch1.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-gcov-switch1.gcno // CHECK-NEXT: -: 0:Data:instrprof-gcov-switch1.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: 1: 1:int main(void) // CHECK-NEXT: -: 2:{ // CHECK-NEXT: 1: 3: int i = 22; diff --git a/compiler-rt/test/profile/Inputs/instrprof-gcov-switch2.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-gcov-switch2.c.gcov index c931365ddf48..f9501e0c870b 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-gcov-switch2.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-gcov-switch2.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-gcov-switch2.gcno // CHECK-NEXT: -: 0:Data:instrprof-gcov-switch2.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: 1: 1:int main(void) // CHECK-NEXT: -: 2:{ // CHECK-NEXT: 1: 3: int i = 22; diff --git a/compiler-rt/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov index 69350471312e..d75a222977a0 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-shared-lib.gcno // CHECK-NEXT: -: 0:Data:instrprof-shared-lib.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: -: 1:int g1 = 0; // CHECK-NEXT: -: 2:int g2 = 1; // CHECK-NEXT: -: 3: diff --git a/compiler-rt/test/profile/Inputs/instrprof-shared-main.c.gcov b/compiler-rt/test/profile/Inputs/instrprof-shared-main.c.gcov index a31a60238809..24facb5e1a38 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-shared-main.c.gcov +++ b/compiler-rt/test/profile/Inputs/instrprof-shared-main.c.gcov @@ -2,7 +2,6 @@ // CHECK-NEXT: -: 0:Graph:instrprof-shared-main.gcno // CHECK-NEXT: -: 0:Data:instrprof-shared-main.gcda // CHECK-NEXT: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 // CHECK-NEXT: -: 1:extern int g1, g2; // CHECK-NEXT: -: 2:extern void foo(int n); // CHECK-NEXT: -: 3: diff --git a/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c b/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c index ca13a0896a7b..96cf4296524d 100644 --- a/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c +++ b/compiler-rt/test/profile/gcov-__gcov_flush-terminate.c @@ -8,7 +8,6 @@ // RUN: llvm-cov gcov -t gcov-__gcov_flush-terminate.gcda | FileCheck %s // CHECK: -: 0:Runs:1 -// CHECK-NEXT: -: 0:Programs:1 void __gcov_dump(void); void __gcov_reset(void); diff --git a/compiler-rt/test/profile/lit.cfg.py b/compiler-rt/test/profile/lit.cfg.py index 72a389eaf0df..fc2baf7c40b8 100644 --- a/compiler-rt/test/profile/lit.cfg.py +++ b/compiler-rt/test/profile/lit.cfg.py @@ -31,7 +31,7 @@ if ( target_is_msvc = bool(re.match(r".*-windows-msvc$", config.target_triple)) # Whether continous profile collection (%c) requires runtime counter relocation on this platform -runtime_reloc = bool(config.host_os in ["AIX"]) +runtime_reloc = bool(config.host_os in ["AIX", "Linux"]) if config.host_os in ["Linux"]: extra_link_flags = ["-ldl"] @@ -210,3 +210,6 @@ if config.android: if config.have_curl: config.available_features.add("curl") + +if config.host_os in ("AIX", "Darwin", "Linux"): + config.available_features.add("continuous-mode") diff --git a/compiler-rt/test/rtsan/Darwin/dlopen.cpp b/compiler-rt/test/rtsan/Darwin/dlopen.cpp new file mode 100644 index 000000000000..1aabe5cb6e58 --- /dev/null +++ b/compiler-rt/test/rtsan/Darwin/dlopen.cpp @@ -0,0 +1,44 @@ +// Checks that on OS X 10.11+ dlopen'ing a RTsanified library from a +// non-instrumented program exits with a user-friendly message. + +// REQUIRES: osx-autointerception + +// XFAIL: ios + +// RUN: %clangxx -fsanitize=realtime %s -o %t.so -shared -DSHARED_LIB +// RUN: %clangxx %s -o %t + +// RUN: RTSAN_DYLIB_PATH=`%clangxx -fsanitize=realtime %s -### 2>&1 \ +// RUN: | grep "libclang_rt.rtsan_osx_dynamic.dylib" \ +// RUN: | sed -e 's/.*"\(.*libclang_rt.rtsan_osx_dynamic.dylib\)".*/\1/'` + +// Launching a non-instrumented binary that dlopen's an instrumented library should fail. +// RUN: not %run %t %t.so 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL +// Launching a non-instrumented binary with an explicit DYLD_INSERT_LIBRARIES should work. +// RUN: DYLD_INSERT_LIBRARIES=$RTSAN_DYLIB_PATH %run %t %t.so 2>&1 | FileCheck %s + +// Launching an instrumented binary with the DYLD_INSERT_LIBRARIES env variable has no error +// RUN: %clangxx -fsanitize=realtime %s -o %t +// RUN: DYLD_INSERT_LIBRARIES=$RTSAN_DYLIB_PATH %run %t %t.so 2>&1 | FileCheck %s --check-prefix=CHECK-INSTRUMENTED + +#include <dlfcn.h> +#include <stdio.h> + +#if defined(SHARED_LIB) +extern "C" void foo() { fprintf(stderr, "Hello world.\n"); } +#else // defined(SHARED_LIB) +int main(int argc, char *argv[]) { + void *handle = dlopen(argv[1], RTLD_NOW); + void (*foo)() = (void (*)())dlsym(handle, "foo"); + foo(); +} +#endif // defined(SHARED_LIB) + +// CHECK: Hello world. +// CHECK-NOT: ERROR: Interceptors are not working. + +// CHECK-FAIL-NOT: Hello world. +// CHECK-FAIL: ERROR: Interceptors are not working. + +// CHECK-INSTRUMENTED-NOT: ERROR: Interceptors are not working +// CHECK-INSTRUMENTED: Hello world. diff --git a/compiler-rt/test/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt new file mode 100644 index 000000000000..76f57501e854 --- /dev/null +++ b/compiler-rt/test/tysan/CMakeLists.txt @@ -0,0 +1,32 @@ +set(TYSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(TYSAN_TESTSUITES) + +set(TYSAN_TEST_ARCH ${TYSAN_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(TYSAN_SUPPORTED_ARCH TYSAN_TEST_ARCH) +endif() + +foreach(arch ${TYSAN_TEST_ARCH}) + set(TYSAN_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" TYSAN_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} TYSAN_TEST_TARGET_CC TYSAN_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND TYSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +set(TYSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND TYSAN_TEST_DEPS tysan) +endif() + +add_lit_testsuite(check-tysan "Running the TypeSanitizer tests" + ${TYSAN_TESTSUITES} + DEPENDS ${TYSAN_TEST_DEPS} + ) +set_target_properties(check-tysan PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/compiler-rt/test/tysan/anon-ns.cpp b/compiler-rt/test/tysan/anon-ns.cpp new file mode 100644 index 000000000000..681304411df3 --- /dev/null +++ b/compiler-rt/test/tysan/anon-ns.cpp @@ -0,0 +1,41 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o -o %t +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <iostream> + +// This test demonstrates that the types from anonymous namespaces are +// different in different translation units (while the char* type is the same). + +namespace { +struct X { + X(int i, int j) : a(i), b(j) {} + int a; + int b; +}; +} // namespace + +#ifdef PMAIN +void foo(void *context, int i); +char fbyte(void *context); + +int main() { + X x(5, 6); + foo((void *)&x, 8); + std::cout << "fbyte: " << fbyte((void *)&x) << "\n"; +} +#else +void foo(void *context, int i) { + X *x = (X *)context; + x->b = i; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in (anonymous namespace)::X at offset 4) accesses an existing object of type int (in (anonymous namespace)::X at offset 4) + // CHECK: {{#0 0x.* in foo\(void\*, int\) .*anon-ns.cpp:}}[[@LINE-3]] +} + +char fbyte(void *context) { return *(char *)context; } +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/anon-same-struct.c b/compiler-rt/test/tysan/anon-same-struct.c new file mode 100644 index 000000000000..b9044f2a0a73 --- /dev/null +++ b/compiler-rt/test/tysan/anon-same-struct.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +// The two anonymous structs are structurally identical. As a result, we don't +// report an aliasing violation here. +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +typedef struct { + int i1; +} s1; +typedef struct { + int i2; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); +} diff --git a/compiler-rt/test/tysan/anon-struct.c b/compiler-rt/test/tysan/anon-struct.c new file mode 100644 index 000000000000..25f663354592 --- /dev/null +++ b/compiler-rt/test/tysan/anon-struct.c @@ -0,0 +1,27 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +typedef struct { + int i1, i1b; +} s1; +typedef struct { + int i2, i2b, i2c; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in <anonymous type> at offset 0) accesses an existing object of type int (in <anonymous type> at offset 0) + // CHECK: {{#0 0x.* in f .*anon-struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1, .i1b = 5}; + f(&s, (s2 *)&s); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/basic.c b/compiler-rt/test/tysan/basic.c new file mode 100644 index 000000000000..8e66e1a72138 --- /dev/null +++ b/compiler-rt/test/tysan/basic.c @@ -0,0 +1,65 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t 10 >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t 10 >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void __attribute__((noinline)) add_flt(float *a) { + *a += 2.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-3]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-6]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-9]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-12]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-15]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-18]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float partially accesses an object of type short that starts at offset 2 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-21]] +} + +int main(int argc, char *argv[]) { + int x = atoi(argv[1]); + add_flt((float *)&x); + printf("x = %d\n", x); + + long y = x; + add_flt((float *)&y); + printf("y = %ld\n", y); + + add_flt(((float *)&y) + 1); + printf("y = %ld\n", y); + + char *mem = (char *)malloc(4 * sizeof(short)); + memset(mem, 0, 4 * sizeof(short)); + *(short *)(mem + 2) = x; + add_flt((float *)mem); + short s1 = *(short *)mem; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + short s2 = *(short *)(mem + 2); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses part of an existing object of type float that starts at offset -2 + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + printf("m[0] = %d, m[1] = %d\n", s1, s2); + free(mem); + + return 0; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/char-memcpy.c b/compiler-rt/test/tysan/char-memcpy.c new file mode 100644 index 000000000000..ebbb6b53d0f3 --- /dev/null +++ b/compiler-rt/test/tysan/char-memcpy.c @@ -0,0 +1,45 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +// There's no type-based-aliasing violation here: the memcpy is implemented +// using only char* or unsigned char* (both of which may alias anything). +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +void my_memcpy_uchar(void *dest, void *src, int n) { + unsigned char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void my_memcpy_char(void *dest, void *src, int n) { + char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void test_uchar() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_uchar(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +void test_char() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_char(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +int main() { + test_uchar(); + test_char(); +} diff --git a/compiler-rt/test/tysan/constexpr-subobject.cpp b/compiler-rt/test/tysan/constexpr-subobject.cpp new file mode 100644 index 000000000000..c473ffe5e445 --- /dev/null +++ b/compiler-rt/test/tysan/constexpr-subobject.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck --allow-empty %s < %t.out + +// CHECK-NOT: TypeSanitizer + +int foo() { return 0; } + +struct Bar { + struct S2 { + int (*fnA)(); + int (*fnB)(); + }; + + static int x() { return 0; } + + static const S2 &get() { + static constexpr S2 Info = {&foo, &Bar::x}; + return Info; + } +}; + +int main() { + auto Info = Bar::get(); + return Info.fnB(); +} diff --git a/compiler-rt/test/tysan/global.c b/compiler-rt/test/tysan/global.c new file mode 100644 index 000000000000..247ee768a816 --- /dev/null +++ b/compiler-rt/test/tysan/global.c @@ -0,0 +1,31 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +#include <stdlib.h> +#include <string.h> + +float P; +long L; + +int main() { + *(int *)&P = 5; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + + void *mem = malloc(sizeof(long)); + *(int *)mem = 6; + memcpy(mem, &L, sizeof(L)); + *(int *)mem = 8; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type long + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + int r = *(((int *)mem) + 1); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type int accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + free(mem); + + return r; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/int-long.c b/compiler-rt/test/tysan/int-long.c new file mode 100644 index 000000000000..b7956c07376e --- /dev/null +++ b/compiler-rt/test/tysan/int-long.c @@ -0,0 +1,21 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +long foo(int *x, long *y) { + *x = 0; + *y = 1; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 8 at {{.*}} with type long accesses an existing object of type int + // CHECK: {{#0 0x.* in foo .*int-long.c:}}[[@LINE-3]] + + return *x; +} + +int main(void) { + long l; + printf("%ld\n", foo((int *)&l, &l)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py new file mode 100644 index 000000000000..817a3f0921e8 --- /dev/null +++ b/compiler-rt/test/tysan/lit.cfg.py @@ -0,0 +1,147 @@ +# -*- Python -*- + +import os +import platform +import re +import shlex + +import lit.formats + + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value is not None: + return attr_value + + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name + ) + + +def push_dynamic_library_lookup_path(config, new_path): + if platform.system() == "Windows": + dynamic_library_lookup_var = "PATH" + elif platform.system() == "Darwin": + dynamic_library_lookup_var = "DYLD_LIBRARY_PATH" + else: + dynamic_library_lookup_var = "LD_LIBRARY_PATH" + + new_ld_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path + + if platform.system() == "FreeBSD": + dynamic_library_lookup_var = "LD_32_LIBRARY_PATH" + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_32_library_path + + if platform.system() == "SunOS": + dynamic_library_lookup_var = "LD_LIBRARY_PATH_32" + new_ld_library_path_32 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_32 + + dynamic_library_lookup_var = "LD_LIBRARY_PATH_64" + new_ld_library_path_64 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_64 + + +# Setup config name. +config.name = "TypeSanitizer" + config.name_suffix + +# Platform-specific default TYSAN_OPTIONS for lit tests. +default_tysan_opts = list(config.default_sanitizer_opts) + +default_tysan_opts_str = ":".join(default_tysan_opts) +if default_tysan_opts_str: + config.environment["TYSAN_OPTIONS"] = default_tysan_opts_str + default_tysan_opts_str += ":" +config.substitutions.append( + ("%env_tysan_opts=", "env TYSAN_OPTIONS=" + default_tysan_opts_str) +) + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +if config.host_os not in ["FreeBSD", "NetBSD"]: + libdl_flag = "-ldl" +else: + libdl_flag = "" + +# GCC-ASan doesn't link in all the necessary libraries automatically, so +# we have to do it ourselves. +if config.compiler_id == "GNU": + extra_link_flags = ["-pthread", "-lstdc++", libdl_flag] +else: + extra_link_flags = [] + +# Setup default compiler flags used with -fsanitize=address option. +# FIXME: Review the set of required flags and check if it can be reduced. +target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags +target_cxxflags = config.cxx_mode_flags + target_cflags +clang_tysan_static_cflags = ( + [ + "-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls", + ] + + config.debug_info_flags + + target_cflags +) +if config.target_arch == "s390x": + clang_tysan_static_cflags.append("-mbackchain") +clang_tysan_static_cxxflags = config.cxx_mode_flags + clang_tysan_static_cflags + +clang_tysan_cflags = clang_tysan_static_cflags +clang_tysan_cxxflags = clang_tysan_static_cxxflags + + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + + +config.substitutions.append(("%clang ", build_invocation(target_cflags))) +config.substitutions.append(("%clangxx ", build_invocation(target_cxxflags))) +config.substitutions.append(("%clang_tysan ", build_invocation(clang_tysan_cflags))) +config.substitutions.append(("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags))) + + +# FIXME: De-hardcode this path. +tysan_source_dir = os.path.join( + get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan" +) +python_exec = shlex.quote(get_required_attr(config, "python_executable")) + +# Set LD_LIBRARY_PATH to pick dynamic runtime up properly. +push_dynamic_library_lookup_path(config, config.compiler_rt_libdir) + +# Default test suffixes. +config.suffixes = [".c", ".cpp"] + +if config.host_os == "Darwin": + config.suffixes.append(".mm") + +if config.host_os == "Windows": + config.substitutions.append(("%fPIC", "")) + config.substitutions.append(("%fPIE", "")) + config.substitutions.append(("%pie", "")) +else: + config.substitutions.append(("%fPIC", "-fPIC")) + config.substitutions.append(("%fPIE", "-fPIE")) + config.substitutions.append(("%pie", "-pie")) + +# Only run the tests on supported OSs. +if config.host_os not in [ + "Linux", + "Darwin", +]: + config.unsupported = Tr diff --git a/compiler-rt/test/tysan/lit.site.cfg.py.in b/compiler-rt/test/tysan/lit.site.cfg.py.in new file mode 100644 index 000000000000..b56dce4fed7a --- /dev/null +++ b/compiler-rt/test/tysan/lit.site.cfg.py.in @@ -0,0 +1,17 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.clang = "@TYSAN_TEST_TARGET_CC@" +config.bits = "@TYSAN_TEST_BITS@" +config.arm_thumb = "@COMPILER_RT_ARM_THUMB@" +config.apple_platform = "@TYSAN_TEST_APPLE_PLATFORM@" +config.apple_platform_min_deployment_target_flag = "@TYSAN_TEST_MIN_DEPLOYMENT_TARGET_FLAG@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg.py") diff --git a/compiler-rt/test/tysan/ptr-float.c b/compiler-rt/test/tysan/ptr-float.c new file mode 100644 index 000000000000..aaa989598698 --- /dev/null +++ b/compiler-rt/test/tysan/ptr-float.c @@ -0,0 +1,19 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +float *P; +void zero_array() { + int i; + for (i = 0; i < 1; ++i) + P[i] = 0.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type p1 float + // CHECK: {{#0 0x.* in zero_array .*ptr-float.c:}}[[@LINE-3]] +} + +int main() { + P = (float *)&P; + zero_array(); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp new file mode 100644 index 000000000000..f7baa14d15af --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp @@ -0,0 +1,51 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %s -DPINIT -c -o %tinit.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o %tinit.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +extern "C" { +typedef struct X { + int *start; + int *end; + int i; +} X; +}; + +#ifdef PMAIN +int foo(struct X *); +void bar(struct X *); +void init(struct X *); + +int main() { + struct X x; + init(&x); + printf("%d\n", foo(&x)); + free(x.start); + return 0; +} + +#elif PINIT + +void init(struct X *x) { + x->start = (int *)calloc(100, sizeof(int)); + x->end = x->start + 99; + x->i = 0; +} + +#else + +__attribute__((noinline)) int foo(struct X *x) { + if (x->start < x->end) + return 30; + return 10; +} + +void bar(struct X *x) { x->end = NULL; } + +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset.c b/compiler-rt/test/tysan/struct-offset.c new file mode 100644 index 000000000000..7295e0ae121e --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> +#include <stdlib.h> + +struct X { + int i; + int j; +}; + +int foo(struct X *p, struct X *q) { + q->j = 1; + p->i = 0; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4) + // CHECK: {{#0 0x.* in foo .*struct-offset.c:}}[[@LINE-3]] + return q->j; +} + +int main() { + unsigned char *p = malloc(3 * sizeof(int)); + printf("%i\n", foo((struct X *)(p + sizeof(int)), (struct X *)p)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct.c b/compiler-rt/test/tysan/struct.c new file mode 100644 index 000000000000..f7ecef596762 --- /dev/null +++ b/compiler-rt/test/tysan/struct.c @@ -0,0 +1,39 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +typedef struct S1 { + int i1; +} s1; +typedef struct S2 { + int i2; +} s2; + +void g(int *i) { + *i = 5; + printf("%i\n", *i); +} + +void h(char *c) { + *c = 5; + printf("%i\n", (int)*c); +} + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in S2 at offset 0) accesses an existing object of type int (in S1 at offset 0) + // CHECK: {{#0 0x.* in f .*struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); + g(&s.i1); + h((char *)&s.i1); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/union-wr-wr.c b/compiler-rt/test/tysan/union-wr-wr.c new file mode 100644 index 000000000000..6414bbfcf9d9 --- /dev/null +++ b/compiler-rt/test/tysan/union-wr-wr.c @@ -0,0 +1,18 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +int main() { + union { + int i; + short s; + } u; + + u.i = 42; + u.s = 1; + + printf("%d\n", u.i); +} diff --git a/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c new file mode 100644 index 000000000000..b3d8b0a6465f --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr45282.c @@ -0,0 +1,32 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/45282 + +#include <stdio.h> + +int main(void) { + + double a[29], b[20]; + int i, j; + + for (i = 0; i < 20; ++i) { + b[i] = 2.01f + 1.f; + ((float *)a)[i] = 2.01f * 2.0145f; + ((float *)a + 38)[i] = 2.01f * 1.0123f; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 8 at {{.+}} with type double accesses an existing object of type float + // CHECK-NEXT: in main {{.*/?}}violation-pr45282.c:25 + + // loop of problems + for (j = 2; j <= 4; ++j) { + a[j - 1] = ((float *)a)[j] * ((float *)a + 38)[j - 1]; + ((float *)a + 38)[j - 1] = ((float *)a)[j - 1] + b[j - 1]; + } + + printf("((float *)a + 38)[2] = %f\n", ((float *)a + 38)[2]); + + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c new file mode 100644 index 000000000000..fb895ff729de --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr47137.c @@ -0,0 +1,41 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/47137 +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +void f(int m) { + int n = (4 * m + 2) / 3; + uint64_t *a = malloc(n * sizeof(uint64_t)); + uint64_t *b = malloc(n * sizeof(uint64_t)); + uint64_t aa[] = {0xffff3e0000000001, 0x22eaf0b680a88c16, 0x5a65d25ac40e20f3, + 0x34e7ac346236953e, 0x9dea3e0a26c6ba89, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + uint64_t bb[] = {0x0000000024c0ffff, 0x000000004634d940, 0x00000000219d18ef, + 0x0000000000154519, 0x000000000000035f, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + char l[20]; + l[0] = 0; + for (int i = 0; i < n; i++) { + a[i] = aa[i] + l[0] - '0'; + b[i] = bb[i] + l[0] - '0'; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long + // CHECK-NEXT: in f {{.*/?}}violation-pr47137.c:31 + for (int i = 0, j = 0; j < 4 * m; i += 4, j += 3) { + for (int k = 0; k < 3; k++) { + ((uint16_t *)a)[j + k] = ((uint16_t *)a)[i + k]; + ((uint16_t *)b)[j + k] = ((uint16_t *)b)[i + k]; + } + } + + printf("a: %016llx\n", a[0]); + free(a); + free(b); +} + +int main() { f(6); } diff --git a/compiler-rt/test/tysan/violation-pr51837.c b/compiler-rt/test/tysan/violation-pr51837.c new file mode 100644 index 000000000000..d49a813933d6 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr51837.c @@ -0,0 +1,34 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdint.h> +#include <stdio.h> + +// CHECK-NOT: TypeSanitizer + +union a { + int16_t b; + uint64_t c; +} d; + +uint64_t *e = &d.c; +static uint16_t f(int16_t a, int32_t b, uint64_t c); +static int64_t g(int32_t aa, uint8_t h, union a bb) { + int16_t *i = &d.b; + f(0, h, 0); + *i = h; + return 0; +} +uint16_t f(int16_t a, int32_t b, uint64_t c) { + for (d.c = 0; 0;) + ; + *e = 0; + return 0; +} + +int main() { + uint32_t j = 8; + g(1, j, d); + printf("%d\n", d.b); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr62544.c b/compiler-rt/test/tysan/violation-pr62544.c new file mode 100644 index 000000000000..65dd33327211 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62544.c @@ -0,0 +1,24 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62544 + +int printf(const char *, ...); +int a, b, c; +long d; +int main() { + short *e = &a; + int *f = &a; + *f = 0; + for (; b <= 9; b++) { + int **g = &f; + *f = d; + *g = &c; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in main {{.*/?}}violation-pr62544.c:22 + *e = 3; + printf("%d\n", a); +} diff --git a/compiler-rt/test/tysan/violation-pr62828.cpp b/compiler-rt/test/tysan/violation-pr62828.cpp new file mode 100644 index 000000000000..709132c4aba6 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62828.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62828 +#include <stdio.h> + +typedef int int_v8[8]; +typedef short short_v8[8]; +short *test1(int_v8 *cast_c_array, short_v8 *shuf_c_array1, int *ptr) { + int *input1 = reinterpret_cast<int *>(((int_v8 *)(cast_c_array))); + short *input2 = reinterpret_cast<short *>(reinterpret_cast<int_v8 *>(input1)); + + short *output1 = reinterpret_cast<short *>(((short_v8 *)(shuf_c_array1))); + short *output2 = + reinterpret_cast<short *>(reinterpret_cast<short_v8 *>(output1)); + + for (int r = 0; r < 8; ++r) { + int tmp = (int)((r * 4) + ptr[r]); + if ((ptr[r] / 4) == 0) { + int *input = reinterpret_cast<int *>(((int_v8 *)(cast_c_array))); + input[r] = tmp; + } + } + + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in test1(int (*) [8], short (*) [8], int*) {{.*/?}}violation-pr62828.cpp:29 + for (int i3 = 0; i3 < 4; ++i3) { + output2[i3] = input2[(i3 * 2)]; + } + return output2; +} + +int main() { + int_v8 in[4] = {{4, 4, 4, 4}}; + short_v8 out[4] = {{0}}; + int ptr[8] = {2}; + test1(in, out, ptr); + short *p = reinterpret_cast<short *>(out); + for (int i = 0; i < 32; i++) { + printf("%d ", p[i]); + } + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr68655.cpp b/compiler-rt/test/tysan/violation-pr68655.cpp new file mode 100644 index 000000000000..7be05c7a7d4f --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr68655.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/68655 +struct S1 { + long long a; + long long b; +}; + +// CHECK: TypeSanitizer: type-aliasing-violation on address +// CHECK-NEXT: READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in {{.*}}S1 at offset 0) +// CHECK-NEXT: in copyMem(S1*, S1*) {{.*/?}}violation-pr68655.cpp:19 + +void inline copyMem(S1 *dst, S1 *src) { + unsigned *d = reinterpret_cast<unsigned *>(dst); + unsigned *s = reinterpret_cast<unsigned *>(src); + + for (int i = 0; i < sizeof(S1) / sizeof(unsigned); i++) { + *d = *s; + d++; + s++; + } +} + +void math(S1 *dst, int *srcA, int idx_t) { + S1 zero[4]; + for (int i = 0; i < 2; i++) { + zero[i].a = i + idx_t; + zero[i].b = i * idx_t; + } + + copyMem(&dst[idx_t], &zero[srcA[idx_t]]); +} + +int main() { + S1 dst = {0}; + int Src[2] = {0, 0}; + math(&dst, &Src[0], 0); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr86685.c b/compiler-rt/test/tysan/violation-pr86685.c new file mode 100644 index 000000000000..43b8d478e685 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr86685.c @@ -0,0 +1,29 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include <stdio.h> +#include <stdlib.h> + +// Violation reported in https://github.com/llvm/llvm-project/issues/86685. +void foo(int *s, float *f, long n) { + for (long i = 0; i < n; ++i) { + *f = 2; + if (i == 1) + break; + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 4 at {{.+}} with type int accesses an existing object of type float + // CHECK-NEXT: #0 {{.+}} in foo {{.*/?}}violation-pr86685.c:17 + *s = 4; + } +} + +int main(void) { + union { + int s; + float f; + } u = {0}; + foo(&u.s, &u.f, 2); + printf("%.f\n", u.f); + return 0; +} diff --git a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp new file mode 100644 index 000000000000..5c3bae80ecdd --- /dev/null +++ b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp @@ -0,0 +1,34 @@ +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1 +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3 +// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds %s -O3 -o %t && not %run %t 3 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds -g %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s --check-prefixes=LINE + +#include <cstdlib> + +struct S { + int k; + int l; +}; + +__attribute__((noinline)) void init(S *s) { + __asm__ __volatile__("" : : "r"(s) : "memory"); +} + +__attribute__((noinline, no_sanitize("memory", "address", "hwaddress"))) int +test(char i) { + S a; + init(&a); + S b; + init(&b); + return ((int *)(&a))[i]; + // CHECK: error: access out of bounds + // CHECK: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior + // LINE: local_bounds.cpp:[[#@LINE-3]]:{{.*}}runtime error: access out of bounds + // LINE: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior {{.*}}local_bounds.cpp:[[#@LINE-4]] +} + +int main(int argc, char **argv) { + test(argv[1][0] - '0'); + return 0; +} diff --git a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp new file mode 100644 index 000000000000..c972e1ecfc01 --- /dev/null +++ b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp @@ -0,0 +1,29 @@ +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1 +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3 +// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds %s -O3 -o %t && not --crash %run %t 3 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s + +#include <cstdlib> + +struct S { + int k; + int l; +}; + +__attribute__((noinline)) void init(S *s) { + __asm__ __volatile__("" : : "r"(s) : "memory"); +} + +__attribute__((noinline, no_sanitize("memory"))) int test(char i) { + S a; + init(&a); + S b; + init(&b); + return ((int *)(&a))[i]; + // CHECK: ubsan: local-out-of-bounds by 0x{{[[:xdigit:]]+$}} +} + +int main(int argc, char **argv) { + test(argv[1][0] - '0'); + return 0; +} diff --git a/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c b/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c new file mode 100644 index 000000000000..e11a3712f1be --- /dev/null +++ b/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c @@ -0,0 +1,15 @@ +// RUN: %clang -fsanitize=implicit-integer-sign-change %s -o %t && %run %t 0 2>&1 | FileCheck %s +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +static int Result; + +void __ubsan_report_error(const char *kind, uintptr_t caller) { + fprintf(stderr, "CUSTOM_CALLBACK: %s\n", kind); +} + +int main(int argc, const char **argv) { + int32_t t0 = (~((uint32_t)0)); + // CHECK: CUSTOM_CALLBACK: implicit-conversion +} |
