summaryrefslogtreecommitdiff
path: root/compiler-rt
diff options
context:
space:
mode:
authorMichael Kruse <llvm-project@meinersbur.de>2025-01-03 10:22:51 +0100
committerMichael Kruse <llvm-project@meinersbur.de>2025-01-03 10:22:51 +0100
commit38500d63e14ce340236840f60d356cdefb56a52c (patch)
tree17edbec446ce9b50d2f215a483b83afb293a635d /compiler-rt
parent1a3d5daaef7a6a63448a497da3eff7fc9e23df26 (diff)
parent27f30029741ecf023baece7b3dde1ff9011ffefc (diff)
Merge branch 'main' into users/meinersbur/flang_runtime_split-headersusers/meinersbur/flang_runtime_split-headers
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/CMakeLists.txt2
-rw-r--r--compiler-rt/Maintainers.md110
-rw-r--r--compiler-rt/Maintainers.txt77
-rw-r--r--compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake3
-rw-r--r--compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake1
-rw-r--r--compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake1
-rw-r--r--compiler-rt/cmake/builtin-config-ix.cmake3
-rw-r--r--compiler-rt/cmake/config-ix.cmake15
-rw-r--r--compiler-rt/include/sanitizer/memprof_interface.h6
-rw-r--r--compiler-rt/lib/asan/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/asan/asan_flags.cpp7
-rw-r--r--compiler-rt/lib/asan/asan_interceptors.cpp10
-rw-r--r--compiler-rt/lib/asan/asan_interceptors.h6
-rw-r--r--compiler-rt/lib/asan/asan_interceptors_memintrinsics.h4
-rw-r--r--compiler-rt/lib/asan/tests/CMakeLists.txt4
-rw-r--r--compiler-rt/lib/builtins/CMakeLists.txt9
-rw-r--r--compiler-rt/lib/builtins/aarch64/sme-abi-assert.c11
-rw-r--r--compiler-rt/lib/builtins/aarch64/sme-abi-init.c50
-rw-r--r--compiler-rt/lib/builtins/aarch64/sme-abi-vg.c18
-rw-r--r--compiler-rt/lib/builtins/aarch64/sme-abi.S237
-rw-r--r--compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S94
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64.c2
-rw-r--r--compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc31
-rw-r--r--compiler-rt/lib/builtins/fp_div_impl.inc7
-rw-r--r--compiler-rt/lib/builtins/truncxfhf2.c15
-rw-r--r--compiler-rt/lib/hwasan/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/interception/interception.h2
-rw-r--r--compiler-rt/lib/interception/interception_win.cpp56
-rw-r--r--compiler-rt/lib/interception/tests/interception_win_test.cpp4
-rw-r--r--compiler-rt/lib/memprof/memprof_allocator.cpp3
-rw-r--r--compiler-rt/lib/memprof/memprof_flags.cpp2
-rw-r--r--compiler-rt/lib/memprof/memprof_flags.h16
-rw-r--r--compiler-rt/lib/memprof/memprof_flags.inc5
-rw-r--r--compiler-rt/lib/memprof/memprof_interceptors.cpp10
-rw-r--r--compiler-rt/lib/memprof/memprof_interceptors.h6
-rw-r--r--compiler-rt/lib/memprof/memprof_interceptors_memintrinsics.h4
-rw-r--r--compiler-rt/lib/memprof/memprof_interface_internal.h3
-rw-r--r--compiler-rt/lib/memprof/memprof_rtl.cpp2
-rw-r--r--compiler-rt/lib/memprof/weak_symbols.txt2
-rw-r--r--compiler-rt/lib/msan/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/msan/msan_interceptors.cpp4
-rw-r--r--compiler-rt/lib/msan/msan_poisoning.cpp6
-rw-r--r--compiler-rt/lib/nsan/nsan_allocator.cpp4
-rw-r--r--compiler-rt/lib/nsan/nsan_interceptors.cpp23
-rw-r--r--compiler-rt/lib/orc/CMakeLists.txt7
-rw-r--r--compiler-rt/lib/orc/macho_tlv.x86-64.S2
-rw-r--r--compiler-rt/lib/orc/resolve.cpp49
-rw-r--r--compiler-rt/lib/orc/sysv_reenter.arm64.S102
-rw-r--r--compiler-rt/lib/orc/sysv_reenter.x86-64.S81
-rw-r--r--compiler-rt/lib/orc/tests/unit/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/orc/tests/unit/common.cpp6
-rw-r--r--compiler-rt/lib/profile/InstrProfilingMerge.c56
-rw-r--r--compiler-rt/lib/rtsan/rtsan.cpp3
-rw-r--r--compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp70
-rw-r--r--compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp70
-rw-r--r--compiler-rt/lib/rtsan/tests/rtsan_test_main.cpp5
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc44
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc34
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h6
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp5
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h6
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_win.cpp19
-rw-r--r--compiler-rt/lib/scudo/standalone/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h30
-rw-r--r--compiler-rt/lib/scudo/standalone/list.h39
-rw-r--r--compiler-rt/lib/scudo/standalone/primary32.h25
-rw-r--r--compiler-rt/lib/scudo/standalone/primary64.h10
-rw-r--r--compiler-rt/lib/scudo/standalone/release.h8
-rw-r--r--compiler-rt/lib/scudo/standalone/type_traits.h47
-rw-r--r--compiler-rt/lib/tsan/rtl/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp4
-rw-r--r--compiler-rt/lib/tysan/CMakeLists.txt79
-rw-r--r--compiler-rt/lib/tysan/lit.cfg35
-rw-r--r--compiler-rt/lib/tysan/lit.site.cfg.in12
-rw-r--r--compiler-rt/lib/tysan/tysan.cpp346
-rw-r--r--compiler-rt/lib/tysan/tysan.h78
-rw-r--r--compiler-rt/lib/tysan/tysan.syms.extra2
-rw-r--r--compiler-rt/lib/tysan/tysan_flags.inc17
-rw-r--r--compiler-rt/lib/tysan/tysan_interceptors.cpp237
-rw-r--r--compiler-rt/lib/tysan/tysan_platform.h93
-rw-r--r--compiler-rt/lib/ubsan/CMakeLists.txt3
-rw-r--r--compiler-rt/lib/ubsan/ubsan_checks.inc1
-rw-r--r--compiler-rt/lib/ubsan/ubsan_handlers.cpp32
-rw-r--r--compiler-rt/lib/ubsan/ubsan_handlers.h3
-rw-r--r--compiler-rt/lib/ubsan/ubsan_interface.inc2
-rw-r--r--compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp101
-rw-r--r--compiler-rt/lib/xray/CMakeLists.txt12
-rw-r--r--compiler-rt/lib/xray/xray_interface.cpp4
-rw-r--r--compiler-rt/lib/xray/xray_riscv.cpp266
-rw-r--r--compiler-rt/lib/xray/xray_trampoline_riscv32.S89
-rw-r--r--compiler-rt/lib/xray/xray_trampoline_riscv64.S89
-rw-r--r--compiler-rt/lib/xray/xray_trampoline_riscv_common.S96
-rw-r--r--compiler-rt/lib/xray/xray_tsc.h2
-rw-r--r--compiler-rt/test/asan/TestCases/Linux/global-overflow-bfd.cpp3
-rw-r--r--compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp2
-rw-r--r--compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp34
-rw-r--r--compiler-rt/test/builtins/Unit/divdf3_test.c4
-rw-r--r--compiler-rt/test/builtins/Unit/divsf3_test.c4
-rw-r--r--compiler-rt/test/builtins/Unit/divtf3_test.c5
-rw-r--r--compiler-rt/test/builtins/Unit/truncxfhf2_test.c74
-rw-r--r--compiler-rt/test/fuzzer/noasan-strcmp.test2
-rw-r--r--compiler-rt/test/memprof/TestCases/default_options.cpp3
-rw-r--r--compiler-rt/test/memprof/TestCases/dump_at_exit.cpp16
-rw-r--r--compiler-rt/test/memprof/TestCases/set_options.cpp16
-rw-r--r--compiler-rt/test/orc/TestCases/Generic/Inputs/foo-ret-42.ll4
-rw-r--r--compiler-rt/test/orc/TestCases/Generic/Inputs/var-x-42.ll1
-rw-r--r--compiler-rt/test/orc/TestCases/Generic/lazy-link.ll30
-rw-r--r--compiler-rt/test/orc/TestCases/Generic/orc-rt-executor-usage.test6
-rw-r--r--compiler-rt/test/orc/lit.cfg.py5
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/basic.c2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/get-filename.c2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/image-with-mcdc.c2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/multi-threaded.cpp2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/online-merging.c2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/pid-substitution.c2
-rw-r--r--compiler-rt/test/profile/ContinuousSyncMode/set-filename.c2
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-gcov-switch1.c.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-gcov-switch2.c.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov1
-rw-r--r--compiler-rt/test/profile/Inputs/instrprof-shared-main.c.gcov1
-rw-r--r--compiler-rt/test/profile/gcov-__gcov_flush-terminate.c1
-rw-r--r--compiler-rt/test/profile/lit.cfg.py5
-rw-r--r--compiler-rt/test/rtsan/Darwin/dlopen.cpp44
-rw-r--r--compiler-rt/test/tysan/CMakeLists.txt32
-rw-r--r--compiler-rt/test/tysan/anon-ns.cpp41
-rw-r--r--compiler-rt/test/tysan/anon-same-struct.c26
-rw-r--r--compiler-rt/test/tysan/anon-struct.c27
-rw-r--r--compiler-rt/test/tysan/basic.c65
-rw-r--r--compiler-rt/test/tysan/char-memcpy.c45
-rw-r--r--compiler-rt/test/tysan/constexpr-subobject.cpp25
-rw-r--r--compiler-rt/test/tysan/global.c31
-rw-r--r--compiler-rt/test/tysan/int-long.c21
-rw-r--r--compiler-rt/test/tysan/lit.cfg.py147
-rw-r--r--compiler-rt/test/tysan/lit.site.cfg.py.in17
-rw-r--r--compiler-rt/test/tysan/ptr-float.c19
-rw-r--r--compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp51
-rw-r--r--compiler-rt/test/tysan/struct-offset.c26
-rw-r--r--compiler-rt/test/tysan/struct.c39
-rw-r--r--compiler-rt/test/tysan/union-wr-wr.c18
-rw-r--r--compiler-rt/test/tysan/violation-pr45282.c32
-rw-r--r--compiler-rt/test/tysan/violation-pr47137.c41
-rw-r--r--compiler-rt/test/tysan/violation-pr51837.c34
-rw-r--r--compiler-rt/test/tysan/violation-pr62544.c24
-rw-r--r--compiler-rt/test/tysan/violation-pr62828.cpp44
-rw-r--r--compiler-rt/test/tysan/violation-pr68655.cpp40
-rw-r--r--compiler-rt/test/tysan/violation-pr86685.c29
-rw-r--r--compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp34
-rw-r--r--compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp29
-rw-r--r--compiler-rt/test/ubsan_minimal/TestCases/override-callback.c15
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, &quotient_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
+}