llvm-project/compiler-rt/lib/nsan/CMakeLists.txt
Fangrui Song a853fe25df
[nsan] Add nsan_preinit.cpp and make it static library only
#94322 defines .preinit_array to initialize nsan early.
DT_PREINIT_ARRAY can only be used with the main executable. GNU ld would
complain when a DSO has .preinit_array. Therefore,
nsan_preinit.cpp cannot be linked into `libclang_rt.nsan.so` (#98415).

Working with @alexander-shaposhnikov, we noticed that `Nsan-x86_64-Test
--gtest_output=json` without `.preinit_array` will sigsegv. This is
because googletest with the JSON output calls `localtime_r` , which
calls `free(0)` and fails when `REAL(free)` remains uninitialized
(nullptr). This is benign with the default output because malloc/free
are all paired and `REAL(free)(ptr)` is not called.

To fix the unittest failure, `__nsan_init` needs to be called early
(.preinit_array).
`asan/tests/CMakeLists.txt:ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS` ues
`-fsanitize=address` to ensure `asan_preinit.cpp.o` is linked into the
unittest executable. Port the approach and remove
`NSAN_TEST_RUNTIME_OBJECTS`.

Fix #98523

Pull Request: https://github.com/llvm/llvm-project/pull/98564
2024-07-11 18:22:52 -07:00

133 lines
3.8 KiB
CMake

add_compiler_rt_component(nsan)
include_directories(..)
set(NSAN_SOURCES
nsan.cpp
nsan_flags.cpp
nsan_interceptors.cpp
nsan_malloc_linux.cpp
nsan_stats.cpp
nsan_suppressions.cpp
)
set(NSAN_PREINIT_SOURCES
nsan_preinit.cpp)
set(NSAN_HEADERS
nsan.h
nsan_flags.h
nsan_flags.inc
nsan_platform.h
nsan_stats.h
nsan_suppressions.h
)
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})
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})
add_compiler_rt_object_libraries(RTNsan_preinit
ARCHS ${NSAN_SUPPORTED_ARCH}
SOURCES ${NSAN_PREINIT_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 ${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_preinit 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)
endif()