diff --git a/CMakeLists.txt b/CMakeLists.txt index de11a4d3e0c..a4b6b9233eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,13 +346,35 @@ target_link_libraries(core_interface INTERFACE Threads::Threads ) +# Define "sanitize_interface" with flags intended to apply to all libraries and +# executables to support sanitizers and fuzzing, and a separate +# "fuzzer_interface" with flags specifically intended to apply to the fuzz test +# binary. Reason these are separate interfaces is that if -DSANITIZERS=fuzzer is +# specified, the fuzz test binary should be built with -fsanitize=fuzzer (so it +# can use libFuzzer's main function), but libraries should be built with +# -fsanitize=fuzzer-no-link (so they can be linked into other executables that +# have their own main functions). add_library(sanitize_interface INTERFACE) +add_library(fuzzer_interface INTERFACE) target_link_libraries(core_interface INTERFACE sanitize_interface) if(SANITIZERS) + # Transform list of sanitizers into -fsanitize flags, replacing "fuzzer" with + # "fuzzer-no-link" in sanitize_interface flags, and moving "fuzzer" to + # fuzzer_interface flags. + string(REGEX REPLACE "(^|,)fuzzer($|,)" "\\1fuzzer-no-link\\2" SANITIZE_FLAG "${SANITIZERS}") + set(FUZZ_FLAG "") + if (NOT "${SANITIZE_FLAG}" STREQUAL "${SANITIZERS}") + set(FUZZ_FLAG "-fsanitize=fuzzer") + if(NOT BUILD_FOR_FUZZING) + message(FATAL_ERROR "Error: Enabling -DSANITIZERS=fuzzer without -DBUILD_FOR_FUZZING=ON is not supported.") + endif() + endif() + set(SANITIZE_FLAG "-fsanitize=${SANITIZE_FLAG}") + # First check if the compiler accepts flags. If an incompatible pair like # -fsanitize=address,thread is used here, this check will fail. This will also # fail if a bad argument is passed, e.g. -fsanitize=undfeined - try_append_cxx_flags("-fsanitize=${SANITIZERS}" TARGET sanitize_interface + try_append_cxx_flags("${SANITIZE_FLAG}" TARGET sanitize_interface RESULT_VAR cxx_supports_sanitizers SKIP_LINK ) @@ -365,12 +387,11 @@ if(SANITIZERS) # flag. This is a separate check so we can give a better error message when # the sanitize flags are supported by the compiler but the actual sanitizer # libs are missing. - try_append_linker_flag("-fsanitize=${SANITIZERS}" VAR SANITIZER_LDFLAGS + try_append_linker_flag("${SANITIZE_FLAG}" VAR SANITIZER_LDFLAGS SOURCE " #include #include extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } - __attribute__((weak)) // allow for libFuzzer linking int main() { return 0; } " RESULT_VAR linker_supports_sanitizers @@ -380,6 +401,7 @@ if(SANITIZERS) endif() endif() target_link_options(sanitize_interface INTERFACE ${SANITIZER_LDFLAGS}) +target_link_options(fuzzer_interface INTERFACE ${FUZZ_FLAG}) if(BUILD_FUZZ_BINARY) target_link_libraries(core_interface INTERFACE ${FUZZ_LIBS}) @@ -390,7 +412,7 @@ if(BUILD_FUZZ_BINARY) extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } // No main() function. " FUZZ_BINARY_LINKS_WITHOUT_MAIN_FUNCTION - LDFLAGS ${SANITIZER_LDFLAGS} + LDFLAGS ${SANITIZER_LDFLAGS} ${FUZZ_FLAG} LINK_LIBRARIES ${FUZZ_LIBS} ) endif() diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index e99c6d91f47..88abd0e6cef 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -137,6 +137,7 @@ add_executable(fuzz ) target_link_libraries(fuzz core_interface + fuzzer_interface test_fuzz bitcoin_cli bitcoin_common