[compiler-rt] Build custom libcxx with libcxxabi

This changes add_custom_libcxx to also build libcxxabi and merges
the two into a static and hermetic library.
There are multiple advantages:
1) The resulting libFuzzer doesn't expose C++ internals and looks
   like a plain C library.
2) We don't have to manually link in libstdc++ to provide cxxabi.
3) The sanitizer tests cannot interfere with an installed version
   of libc++.so in LD_LIBRARY_PATH.

Differential Revision: https://reviews.llvm.org/D58013

llvm-svn: 354212
This commit is contained in:
Jonas Hahnfeld 2019-02-17 12:16:20 +00:00
parent 91ecb69acd
commit 66c60d9d71
16 changed files with 74 additions and 46 deletions

View File

@ -484,6 +484,15 @@ if(COMPILER_RT_USE_LIBCXX)
break()
endif()
endforeach()
foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxxabi
${LLVM_MAIN_SRC_DIR}/runtimes/libcxxabi
${LLVM_MAIN_SRC_DIR}/../libcxxabi
${LLVM_EXTERNAL_LIBCXXABI_SOURCE_DIR})
if(IS_DIRECTORY ${path})
set(COMPILER_RT_LIBCXXABI_PATH ${path})
break()
endif()
endforeach()
endif()
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)

View File

@ -509,6 +509,9 @@ macro(add_custom_libcxx name prefix)
if(NOT COMPILER_RT_LIBCXX_PATH)
message(FATAL_ERROR "libcxx not found!")
endif()
if(NOT COMPILER_RT_LIBCXXABI_PATH)
message(FATAL_ERROR "libcxxabi not found!")
endif()
cmake_parse_arguments(LIBCXX "USE_TOOLCHAIN" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN})
@ -584,7 +587,7 @@ macro(add_custom_libcxx name prefix)
ExternalProject_Add(${name}
DEPENDS ${name}-clobber ${LIBCXX_DEPS}
PREFIX ${prefix}
SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH}
SOURCE_DIR ${COMPILER_RT_SOURCE_DIR}/cmake/Modules/CustomLibcxx
STAMP_DIR ${STAMP_DIR}
BINARY_DIR ${BINARY_DIR}
CMAKE_ARGS ${CMAKE_PASSTHROUGH_VARIABLES}
@ -595,7 +598,8 @@ macro(add_custom_libcxx name prefix)
-DLLVM_PATH=${LLVM_MAIN_SRC_DIR}
-DLLVM_BINARY_DIR=${prefix}
-DLLVM_LIBRARY_OUTPUT_INTDIR=${prefix}/lib
-DLIBCXX_STANDALONE_BUILD=ON
-DCOMPILER_RT_LIBCXX_PATH=${COMPILER_RT_LIBCXX_PATH}
-DCOMPILER_RT_LIBCXXABI_PATH=${COMPILER_RT_LIBCXXABI_PATH}
${LIBCXX_CMAKE_ARGS}
INSTALL_COMMAND ""
STEP_TARGETS configure build

View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.4.3)
# Build static libcxxabi.
set(LIBCXXABI_STANDALONE_BUILD 1)
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE STRING "")
set(LIBCXXABI_LIBCXX_PATH ${COMPILER_RT_LIBCXX_PATH} CACHE PATH "")
set(LIBCXXABI_INCLUDE_TESTS OFF CACHE BOOL "")
add_subdirectory(${COMPILER_RT_LIBCXXABI_PATH} ${CMAKE_CURRENT_BINARY_DIR}/cxxabi)
# Build static libcxx without exceptions.
set(LIBCXX_STANDALONE_BUILD 1)
set(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY OFF CACHE BOOL "")
set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
# Use above libcxxabi.
set(LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "")
set(LIBCXX_CXX_ABI_INTREE 1)
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(LIBCXX_CXX_ABI_INCLUDE_PATHS ${COMPILER_RT_LIBCXXABI_PATH}/include CACHE PATH "")
add_subdirectory(${COMPILER_RT_LIBCXX_PATH} ${CMAKE_CURRENT_BINARY_DIR}/cxx)

View File

@ -55,7 +55,9 @@ CHECK_CXX_SOURCE_COMPILES("
set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
if(OS_NAME MATCHES "Linux|Fuchsia" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
list(APPEND LIBFUZZER_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer)
# Remove -stdlib= which is unused when passing -nostdinc++.
string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
@ -113,7 +115,9 @@ add_compiler_rt_runtime(clang_rt.fuzzer_no_main
CFLAGS ${LIBFUZZER_CFLAGS}
PARENT_TARGET fuzzer)
if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
if(OS_NAME MATCHES "Linux|Fuchsia" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
macro(partially_link_libcxx name dir arch)
set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir")
file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir})
@ -131,13 +135,8 @@ if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch})
add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX}
CFLAGS ${TARGET_CFLAGS}
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=1
-fvisibility=hidden
CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
-DLIBCXX_ENABLE_EXCEPTIONS=OFF
-DLIBCXX_ENABLE_SHARED=OFF
-DLIBCXX_ABI_NAMESPACE=Fuzzer
-DLIBCXX_CXX_ABI=none)
-DLIBCXX_ABI_NAMESPACE=Fuzzer)
target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build)
target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)

View File

@ -24,7 +24,9 @@ if(NOT WIN32)
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lpthread)
endif()
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++)
endif()
@ -46,7 +48,9 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
FOLDER "Compiler-RT Runtime tests")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
file(GLOB libfuzzer_headers ../*.h)
set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build ${libfuzzer_headers})
set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)

View File

@ -48,10 +48,8 @@ set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
)
set(MSAN_UNITTEST_LINK_FLAGS
-fsanitize=memory
# Don't need -stdlib=libc++ because we explicitly list libc++.so in the linker
# Don't need -stdlib=libc++ because we explicitly list libc++.a in the linker
# inputs.
# FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
-lstdc++
)
append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
@ -116,16 +114,16 @@ macro(add_msan_tests_for_arch arch kind cflags)
endif()
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
add_compiler_rt_test(MsanUnitTests "Msan-${arch}${kind}-Test" ${arch}
OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
OBJECTS ${MSAN_TEST_OBJECTS} "${MSAN_LIBCXX_DIR}/libc++.a"
DEPS ${MSAN_TEST_DEPS}
LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
${TARGET_LINK_FLAGS}
"-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
"-Wl,-rpath=${LIBCXX_PREFIX}/lib")
${TARGET_LINK_FLAGS})
endmacro()
# We should only build MSan unit tests if we can build instrumented libcxx.
if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_LIBCXX_PATH)
if(COMPILER_RT_CAN_EXECUTE_TESTS AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
foreach(arch ${MSAN_SUPPORTED_ARCH})
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch})
@ -133,7 +131,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_LIBCXX_PATH)
DEPS ${MSAN_RUNTIME_LIBRARIES}
CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS}
USE_TOOLCHAIN)
set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
set(MSAN_LIBCXX_DIR ${LIBCXX_PREFIX}/lib/)
add_msan_tests_for_arch(${arch} "" "")
add_msan_tests_for_arch(${arch} "-with-call"

View File

@ -236,6 +236,7 @@ endif()
# Build libcxx instrumented with TSan.
if(COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH AND
COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang" AND
NOT ANDROID)
set(libcxx_tsan_deps)

View File

@ -63,17 +63,6 @@ config.substitutions.append(('%libfuzzer_src', libfuzzer_src_root))
def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
compiler_cmd = config.clang
extra_cmd = config.target_flags
if config.clang and config.stdlib == 'libc++':
link_cmd = '-stdlib=libc++ -Wl,-rpath=%s' % config.runtime_library_dir
elif config.clang and config.stdlib == 'static-libc++':
link_cmd = '-stdlib=libc++ -lc++abi -static-libstdc++ -Wl,-rpath=%s' % (
config.runtime_library_dir)
elif any(x in config.target_triple for x in ('darwin', 'freebsd')):
link_cmd = '-lc++'
elif 'windows-msvc' in config.target_triple:
link_cmd = ''
else:
link_cmd = '-lstdc++'
if is_cpp and 'windows-msvc' in config.target_triple:
std_cmd = '--driver-mode=cl'
@ -92,7 +81,6 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
return " ".join([
compiler_cmd,
std_cmd,
link_cmd,
"-O2 -gline-tables-only",
sanitizers_cmd,
"-I%s" % libfuzzer_src_root,

View File

@ -43,7 +43,9 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND MSAN_TEST_DEPS msan)
endif()
if(COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_LIBCXX_PATH)
if(COMPILER_RT_INCLUDE_TESTS AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)

View File

@ -8,6 +8,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND TSAN_TEST_DEPS tsan)
endif()
if(COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH AND
COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang"
AND NOT APPLE AND NOT ANDROID)
list(APPEND TSAN_TEST_DEPS libcxx_tsan)

View File

@ -1,8 +1,8 @@
// Test that verifies TSan runtime doesn't contain compiler-emitted
// memcpy/memmove calls. It builds the binary with TSan and passes it to
// check_memcpy.sh script.
// memcpy/memmove calls. It builds the binary with TSan and check's
// its objdump.
// RUN: %clangxx_tsan -O1 %s -o %t
// RUN: %clang_tsan -O1 %s -o %t
// RUN: llvm-objdump -d %t | FileCheck %s
// REQUIRES: compiler-rt-optimized

View File

@ -38,7 +38,7 @@ config.substitutions.append(('%env_tsan_opts=',
# GCC driver doesn't add necessary compile/link flags with -fsanitize=thread.
if config.compiler_id == 'GNU':
extra_cflags = ["-fPIE", "-pthread", "-ldl", "-lstdc++", "-lrt", "-pie"]
extra_cflags = ["-fPIE", "-pthread", "-ldl", "-lrt", "-pie"]
else:
extra_cflags = []
@ -59,11 +59,10 @@ if config.has_libcxx and config.host_os != 'Darwin':
"tsan", "libcxx_tsan_%s" % config.target_arch)
libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1")
libcxx_libdir = os.path.join(libcxx_path, "lib")
libcxx_so = os.path.join(libcxx_libdir, "libc++.so")
libcxx_a = os.path.join(libcxx_libdir, "libc++.a")
clang_tsan_cxxflags += ["-nostdinc++",
"-I%s" % libcxx_incdir,
libcxx_so,
"-Wl,-rpath=%s" % libcxx_libdir]
libcxx_a]
def build_invocation(compile_flags):
return " " + " ".join([config.clang] + compile_flags) + " "

View File

@ -1,5 +1,4 @@
// RUN: %clangxx_tsan %linux_static_libstdcplusplus -O1 %s -o %t && %run %t 2>&1 \
// RUN: | FileCheck %s
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

View File

@ -23,7 +23,7 @@ set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXX_STANDALONE_BUILD)
project(libcxx CXX C)
set(PACKAGE_NAME libcxx)

View File

@ -98,7 +98,7 @@ if ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libstdc++" OR
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libcxxabi")
if (LIBCXX_CXX_ABI_INTREE)
# Link against just-built "cxxabi" target.
if (LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY)
if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
set(CXXABI_LIBNAME cxxabi_static)
else()
set(CXXABI_LIBNAME cxxabi_shared)

View File

@ -17,7 +17,7 @@ set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXXABI_STANDALONE_BUILD)
project(libcxxabi CXX C)
set(PACKAGE_NAME libcxxabi)