[compiler-rt] 80ff3ac - [nsan] Add shared runtime
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 10 18:35:08 PDT 2024
Author: Fangrui Song
Date: 2024-07-10T18:35:05-07:00
New Revision: 80ff3acd364810ec11efd45c2ce98a1bf9ce0f73
URL: https://github.com/llvm/llvm-project/commit/80ff3acd364810ec11efd45c2ce98a1bf9ce0f73
DIFF: https://github.com/llvm/llvm-project/commit/80ff3acd364810ec11efd45c2ce98a1bf9ce0f73.diff
LOG: [nsan] Add shared runtime
so that `clang -fsanitize=numerical -shared-libsan` will use
`libclang_rt.nsan.so` on Linux.
Shared runtime is preferred for some platforms (Android, Apple, Fuchsia;
though they are not supported yet) and helps plugin use cases (#98302).
* Update `ninja nsan` to build `libclang_rt.nsan.so`
* Fix `nsan.syms.extra`: `nsan_*` is unneeded. Add `__ubsan_*` so that
`-fsanitize=numerical,undefined -shared-libsan` works.
* Move allocation functions to `nsan_malloc_linux.cpp`. While Apple
platforms aren't supported yet, this separation makes it easier to add
Apple support.
* Delete interceptors for very obsoleted pvalloc/valloc but retain
memalign.
* Replace `HandleEarlyAlloc` with `DlsymAlloc`.
Pull Request: https://github.com/llvm/llvm-project/pull/98415
Added:
compiler-rt/lib/nsan/nsan_malloc_linux.cpp
Modified:
compiler-rt/lib/nsan/CMakeLists.txt
compiler-rt/lib/nsan/nsan.h
compiler-rt/lib/nsan/nsan.syms.extra
compiler-rt/lib/nsan/nsan_interceptors.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/nsan/CMakeLists.txt b/compiler-rt/lib/nsan/CMakeLists.txt
index aef9b651ab2ec..d67c3ac434d3a 100644
--- a/compiler-rt/lib/nsan/CMakeLists.txt
+++ b/compiler-rt/lib/nsan/CMakeLists.txt
@@ -6,6 +6,7 @@ set(NSAN_SOURCES
nsan.cpp
nsan_flags.cpp
nsan_interceptors.cpp
+ nsan_malloc_linux.cpp
nsan_stats.cpp
nsan_suppressions.cpp
)
@@ -24,30 +25,98 @@ append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC NSAN_CFLAGS)
set(NSAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
set(NSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+set(NSAN_DYNAMIC_CFLAGS ${NSAN_CFLAGS})
-foreach(arch ${NSAN_SUPPORTED_ARCH})
- add_compiler_rt_runtime(
- clang_rt.nsan
- STATIC
- ARCHS ${arch}
- SOURCES ${NSAN_SOURCES}
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
- $<TARGET_OBJECTS:RTUbsan.${arch}>
- ADDITIONAL_HEADERS ${NSAN_HEADERS}
- CFLAGS ${NSAN_CFLAGS}
- PARENT_TARGET nsan
- )
-endforeach()
-
-add_compiler_rt_object_libraries(RTNsan
+set(NSAN_COMMON_RUNTIME_OBJECT_LIBS
+ RTInterception
+ RTSanitizerCommon
+ RTSanitizerCommonLibc
+ RTSanitizerCommonCoverage
+ RTSanitizerCommonSymbolizer
+ RTSanitizerCommonSymbolizerInternal
+ RTUbsan)
+
+set(NSAN_DYNAMIC_LIBS
+ ${COMPILER_RT_UNWINDER_LINK_LIBS}
+ ${SANITIZER_CXX_ABI_LIBRARIES}
+ ${SANITIZER_COMMON_LINK_LIBS})
+
+append_list_if(COMPILER_RT_HAS_LIBDL dl NSAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBRT rt NSAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m NSAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread NSAN_DYNAMIC_LIBS)
+
+# Compile sources into an object library.
+
+add_compiler_rt_object_libraries(RTNsan_dynamic
+ ARCHS ${NSAN_SUPPORTED_ARCH}
+ SOURCES ${NSAN_SOURCES}
+ ADDITIONAL_HEADERS ${NSAN_HEADERS}
+ CFLAGS ${NSAN_CFLAGS})
+
+if(NOT APPLE)
+ add_compiler_rt_object_libraries(RTNsan
+ ARCHS ${NSAN_SUPPORTED_ARCH}
+ SOURCES ${NSAN_SOURCES}
+ ADDITIONAL_HEADERS ${NSAN_HEADERS}
+ CFLAGS ${NSAN_CFLAGS})
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "")
+ add_compiler_rt_object_libraries(RTNsan_dynamic_version_script_dummy
ARCHS ${NSAN_SUPPORTED_ARCH}
- SOURCES ${NSAN_SOURCES}
- ADDITIONAL_HEADERS ${NSAN_HEADERS}
- CFLAGS ${NSAN_CFLAGS})
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
+ CFLAGS ${NSAN_DYNAMIC_CFLAGS})
+endif()
+
+add_compiler_rt_runtime(
+ clang_rt.nsan
+ STATIC
+ ARCHS ${NSAN_SUPPORTED_ARCH}
+ OBJECT_LIBS RTNsan
+ ${NSAN_COMMON_RUNTIME_OBJECT_LIBS}
+ CFLAGS ${NSAN_CFLAGS}
+ PARENT_TARGET nsan)
+
+if(NOT APPLE)
+ foreach(arch ${NSAN_SUPPORTED_ARCH})
+ if (COMPILER_RT_HAS_VERSION_SCRIPT)
+ add_sanitizer_rt_version_list(clang_rt.nsan-dynamic-${arch}
+ LIBS clang_rt.nsan-${arch}
+ EXTRA nsan.syms.extra)
+ set(VERSION_SCRIPT_FLAG
+ -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.nsan-dynamic-${arch}.vers)
+ # The Solaris 11.4 linker supports a subset of GNU ld version scripts,
+ # but requires a special option to enable it.
+ if (COMPILER_RT_HAS_GNU_VERSION_SCRIPT_COMPAT)
+ list(APPEND VERSION_SCRIPT_FLAG -Wl,-z,gnu-version-script-compat)
+ endif()
+ set_property(SOURCE
+ ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
+ APPEND PROPERTY
+ OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.nsan-dynamic-${arch}.vers)
+ else()
+ set(VERSION_SCRIPT_FLAG)
+ endif()
+
+ add_compiler_rt_runtime(
+ clang_rt.nsan
+ SHARED
+ ARCHS ${arch}
+ OBJECT_LIBS ${NSAN_COMMON_RUNTIME_OBJECT_LIBS}
+ RTNsan_dynamic
+ # The only purpose of RTNsan_dynamic_version_script_dummy is to
+ # carry a dependency of the shared runtime on the version script.
+ # Replacing it with a straightforward
+ # add_dependencies(clang_rt.nsan-dynamic-${arch} clang_rt.nsan-dynamic-${arch}-version-list)
+ # generates an order-only dependency in ninja.
+ RTNsan_dynamic_version_script_dummy
+ CFLAGS ${NSAN_DYNAMIC_CFLAGS}
+ LINK_FLAGS ${NSAN_DYNAMIC_LINK_FLAGS}
+ ${VERSION_SCRIPT_FLAG}
+ LINK_LIBS ${NSAN_DYNAMIC_LIBS}
+ PARENT_TARGET nsan)
+ endforeach()
+endif()
if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
diff --git a/compiler-rt/lib/nsan/nsan.h b/compiler-rt/lib/nsan/nsan.h
index 896e5379dfc37..0fb998b049854 100644
--- a/compiler-rt/lib/nsan/nsan.h
+++ b/compiler-rt/lib/nsan/nsan.h
@@ -55,6 +55,7 @@ extern bool nsan_initialized;
extern bool nsan_init_is_running;
void InitializeInterceptors();
+void InitializeMallocInterceptors();
// See notes in nsan_platform.
// printf-free (see comment in nsan_interceptors.cc).
diff --git a/compiler-rt/lib/nsan/nsan.syms.extra b/compiler-rt/lib/nsan/nsan.syms.extra
index f3be6d39736b7..53ce5833520b8 100644
--- a/compiler-rt/lib/nsan/nsan.syms.extra
+++ b/compiler-rt/lib/nsan/nsan.syms.extra
@@ -1,2 +1,2 @@
-nsan_*
__nsan_*
+__ubsan_*
diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp
index 68127f169ee46..544b44f53cc42 100644
--- a/compiler-rt/lib/nsan/nsan_interceptors.cpp
+++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp
@@ -1,4 +1,4 @@
-//===-- nsan_interceptors.cc ----------------------------------------------===//
+//===- nsan_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.
@@ -29,26 +29,8 @@ using namespace __sanitizer;
using __nsan::nsan_init_is_running;
using __nsan::nsan_initialized;
-constexpr uptr kEarlyAllocBufSize = 16384;
-static uptr allocated_bytes;
-static char early_alloc_buf[kEarlyAllocBufSize];
-
-static bool isInEarlyAllocBuf(const void *ptr) {
- return ((uptr)ptr >= (uptr)early_alloc_buf &&
- ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf));
-}
-
template <typename T> T min(T a, T b) { return a < b ? a : b; }
-// Handle allocation requests early (before all interceptors are setup). dlsym,
-// for example, calls calloc.
-static void *HandleEarlyAlloc(uptr size) {
- void *Mem = (void *)&early_alloc_buf[allocated_bytes];
- allocated_bytes += size;
- CHECK_LT(allocated_bytes, kEarlyAllocBufSize);
- return Mem;
-}
-
INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
// NOTE: This guard is needed because nsan's initialization code might call
// memset.
@@ -105,90 +87,6 @@ INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) {
return res;
}
-INTERCEPTOR(void *, malloc, uptr size) {
- // NOTE: This guard is needed because nsan's initialization code might call
- // malloc.
- if (nsan_init_is_running && REAL(malloc) == nullptr)
- return HandleEarlyAlloc(size);
-
- void *res = REAL(malloc)(size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
- void *res = REAL(realloc)(ptr, size);
- // FIXME: We might want to copy the types from the original allocation
- // (although that would require that we know its size).
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, calloc, uptr Nmemb, uptr size) {
- // NOTE: This guard is needed because nsan's initialization code might call
- // calloc.
- if (nsan_init_is_running && REAL(calloc) == nullptr) {
- // Note: EarlyAllocBuf is initialized with zeros.
- return HandleEarlyAlloc(Nmemb * size);
- }
-
- void *res = REAL(calloc)(Nmemb, size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), Nmemb * size);
- return res;
-}
-
-INTERCEPTOR(void, free, void *P) {
- // There are only a few early allocation requests, so we simply skip the free.
- if (isInEarlyAllocBuf(P))
- return;
- REAL(free)(P);
-}
-
-INTERCEPTOR(void *, valloc, uptr size) {
- void *const res = REAL(valloc)(size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, memalign, uptr align, uptr size) {
- void *const res = REAL(memalign)(align, size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, __libc_memalign, uptr align, uptr size) {
- void *const res = REAL(__libc_memalign)(align, size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, pvalloc, uptr size) {
- void *const res = REAL(pvalloc)(size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(void *, aligned_alloc, uptr align, uptr size) {
- void *const res = REAL(aligned_alloc)(align, size);
- if (res)
- __nsan_set_value_unknown(static_cast<u8 *>(res), size);
- return res;
-}
-
-INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr size) {
- int res = REAL(posix_memalign)(memptr, align, size);
- if (res == 0 && *memptr)
- __nsan_set_value_unknown(static_cast<u8 *>(*memptr), size);
- return res;
-}
-
INTERCEPTOR(char *, strfry, char *s) {
const auto Len = internal_strlen(s);
char *res = REAL(strfry)(s);
@@ -317,16 +215,7 @@ void __nsan::InitializeInterceptors() {
mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD
#endif
- INTERCEPT_FUNCTION(malloc);
- INTERCEPT_FUNCTION(calloc);
- INTERCEPT_FUNCTION(free);
- INTERCEPT_FUNCTION(realloc);
- INTERCEPT_FUNCTION(valloc);
- INTERCEPT_FUNCTION(memalign);
- INTERCEPT_FUNCTION(__libc_memalign);
- INTERCEPT_FUNCTION(pvalloc);
- INTERCEPT_FUNCTION(aligned_alloc);
- INTERCEPT_FUNCTION(posix_memalign);
+ InitializeMallocInterceptors();
INTERCEPT_FUNCTION(memset);
INTERCEPT_FUNCTION(wmemset);
diff --git a/compiler-rt/lib/nsan/nsan_malloc_linux.cpp b/compiler-rt/lib/nsan/nsan_malloc_linux.cpp
new file mode 100644
index 0000000000000..d66ee65b36747
--- /dev/null
+++ b/compiler-rt/lib/nsan/nsan_malloc_linux.cpp
@@ -0,0 +1,123 @@
+//===- nsan_malloc_linux.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Interceptors for memory allocation functions on ELF OSes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "nsan/nsan.h"
+#include "sanitizer_common/sanitizer_allocator_dlsym.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+#if !SANITIZER_APPLE && !SANITIZER_WINDOWS
+using namespace __sanitizer;
+using __nsan::nsan_initialized;
+
+namespace {
+struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
+ static bool UseImpl() { return !nsan_initialized; }
+};
+} // namespace
+
+INTERCEPTOR(void *, aligned_alloc, uptr align, uptr size) {
+ void *res = REAL(aligned_alloc)(align, size);
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(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)
+ __nsan_set_value_unknown(static_cast<u8 *>(res), nmemb * size);
+ return res;
+}
+
+INTERCEPTOR(void, free, void *ptr) {
+ if (DlsymAlloc::PointerIsMine(ptr))
+ return DlsymAlloc::Free(ptr);
+ REAL(free)(ptr);
+}
+
+INTERCEPTOR(void *, malloc, uptr size) {
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Allocate(size);
+ void *res = REAL(malloc)(size);
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(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);
+ // TODO: We might want to copy the types from the original allocation
+ // (although that would require that we know its size).
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(res), size);
+ return res;
+}
+
+#if SANITIZER_INTERCEPT_REALLOCARRAY
+INTERCEPTOR(void *, reallocarray, void *ptr, uptr nmemb, uptr size) {
+ void *res = REAL(reallocarray)(ptr, nmemb, size);
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(res), nmemb * size);
+ return res;
+}
+#endif // SANITIZER_INTERCEPT_REALLOCARRAY
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr size) {
+ int res = REAL(posix_memalign)(memptr, align, size);
+ if (res == 0 && *memptr)
+ __nsan_set_value_unknown(static_cast<u8 *>(*memptr), size);
+ return res;
+}
+
+// Deprecated allocation functions (memalign, etc).
+#if SANITIZER_INTERCEPT_MEMALIGN
+INTERCEPTOR(void *, memalign, uptr align, uptr size) {
+ void *const res = REAL(memalign)(align, size);
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(res), size);
+ return res;
+}
+
+INTERCEPTOR(void *, __libc_memalign, uptr align, uptr size) {
+ void *const res = REAL(__libc_memalign)(align, size);
+ if (res)
+ __nsan_set_value_unknown(static_cast<u8 *>(res), size);
+ return res;
+}
+#endif
+
+void __nsan::InitializeMallocInterceptors() {
+ INTERCEPT_FUNCTION(aligned_alloc);
+ INTERCEPT_FUNCTION(calloc);
+ INTERCEPT_FUNCTION(free);
+ INTERCEPT_FUNCTION(malloc);
+ INTERCEPT_FUNCTION(posix_memalign);
+ INTERCEPT_FUNCTION(realloc);
+#if SANITIZER_INTERCEPT_REALLOCARRAY
+ INTERCEPT_FUNCTION(reallocarray);
+#endif
+
+#if SANITIZER_INTERCEPT_MEMALIGN
+ INTERCEPT_FUNCTION(memalign);
+ INTERCEPT_FUNCTION(__libc_memalign);
+#endif
+}
+
+#endif
More information about the llvm-commits
mailing list