Skip to content

[nsan] Add shared runtime #98415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 91 additions & 22 deletions compiler-rt/lib/nsan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/nsan/nsan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/nsan/nsan.syms.extra
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
nsan_*
__nsan_*
__ubsan_*
115 changes: 2 additions & 113 deletions compiler-rt/lib/nsan/nsan_interceptors.cpp
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading