Index: lib/Fuzzer/CMakeLists.txt =================================================================== --- lib/Fuzzer/CMakeLists.txt +++ lib/Fuzzer/CMakeLists.txt @@ -1,7 +1,16 @@ -set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}") -# Disable the coverage and sanitizer instrumentation for the fuzzer itself. -set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror") if( LLVM_USE_SANITIZE_COVERAGE ) + # Disable the coverage and sanitizer instrumentation for the fuzzer itself. + # If sanitization of LLVM itself is enabled we rely on the compiler's + # left to right evaluation of compiler flags so that for something like + # ``clang++ -fsanitize=address -fno-sanitize=all`` sanitization will be off. + # FIXME: Stripping out the flags we don't want would probably be a better approach. + set(disable_sanitizer_flags "") + list(APPEND disable_sanitizer_flags + "-fno-sanitize=all" + # FIXME: gcc doesn't know this flag + "-fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters" + "-Werror") + # FIXME: Test the compiler supports those flags add_library(LLVMFuzzerNoMainObjects OBJECT FuzzerCrossOver.cpp FuzzerTraceState.cpp @@ -13,14 +22,17 @@ FuzzerTracePC.cpp FuzzerUtil.cpp ) + target_compile_options(LLVMFuzzerNoMainObjects PRIVATE ${disable_sanitizer_flags}) add_library(LLVMFuzzerNoMain STATIC $ ) + target_compile_options(LLVMFuzzerNoMain PRIVATE ${disable_sanitizer_flags}) target_link_libraries(LLVMFuzzerNoMain ${PTHREAD_LIB}) add_library(LLVMFuzzer STATIC FuzzerMain.cpp $ ) + target_compile_options(LLVMFuzzer PRIVATE ${disable_sanitizer_flags}) target_link_libraries(LLVMFuzzer ${PTHREAD_LIB}) if( LLVM_INCLUDE_TESTS ) Index: lib/Fuzzer/test/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/CMakeLists.txt +++ lib/Fuzzer/test/CMakeLists.txt @@ -1,8 +1,47 @@ +if ("${LLVM_USE_SANITIZER}" STREQUAL "") + message(FATAL_ERROR + "LibFuzzer tests cannot be built without an enabled sanitizer") +endif() +message(STATUS "LibFuzzer test default sanitization: ${LLVM_USE_SANITIZER}") + +function(llvm_append_linker_flag target) + if (NOT (TARGET "${target}")) + message(FATAL_ERROR "Specified target \"${target}\" is not a target") + endif() + foreach(flag ${ARGN}) + set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}") + endforeach() +endfunction() + # Build all these tests with -O0, otherwise optimizations may merge some # basic blocks and we'll fail to discover the targets. -# Also enable the coverage instrumentation back (it is disabled -# for the Fuzzer lib) -set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O0 -fsanitize-coverage=edge,indirect-calls") +# We change the flags for every build type because we might be doing +# a multi-configuration build (e.g. Xcode) where CMAKE_BUILD_TYPE doesn't +# mean anything. +set(variables_to_filter + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL + # FIXME: Optimisation level flags aren't supposed to appear here + # but they do so we have to strip them out + CMAKE_CXX_FLAGS +) +foreach (VARNAME ${variables_to_filter}) + string(REPLACE " " ";" BUILD_FLAGS_AS_LIST "${${VARNAME}}") + set(new_flags "") + foreach (flag ${BUILD_FLAGS_AS_LIST}) + # FIXME: Use of XX here is to avoid CMP0054 + if (NOT ("XX${flag}" MATCHES "XX-O[0123s]")) + set(new_flags "${new_flags} ${flag}") + else() + set(new_flags "${new_flags} -O0") + endif() + endforeach() + set(${VARNAME} "${new_flags}") +endforeach() + +set(SANITIZE_COVERAGE_FLAGS "-fsanitize-coverage=edge,indirect-calls") set(DFSanTests MemcmpTest @@ -67,6 +106,8 @@ add_executable(LLVMFuzzer-${Test} ${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test} PRIVATE ${SANITIZE_COVERAGE_FLAGS}) + llvm_append_linker_flag(LLVMFuzzer-${Test} ${SANITIZE_COVERAGE_FLAGS}) target_link_libraries(LLVMFuzzer-${Test} LLVMFuzzer ) @@ -77,6 +118,8 @@ add_executable(LLVMFuzzer-${Test} ${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test} PRIVATE ${SANITIZE_COVERAGE_FLAGS}) + llvm_append_linker_flag(LLVMFuzzer-${Test} ${SANITIZE_COVERAGE_FLAGS}) target_link_libraries(LLVMFuzzer-${Test} LLVMFuzzerNoMain ) @@ -103,6 +146,8 @@ $ ) +target_compile_options(LLVMFuzzer-Unittest PRIVATE ${SANITIZE_COVERAGE_FLAGS}) +llvm_append_linker_flag(LLVMFuzzer-Unittest ${SANITIZE_COVERAGE_FLAGS}) target_link_libraries(LLVMFuzzer-Unittest gtest gtest_main Index: lib/Fuzzer/test/dfsan/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/dfsan/CMakeLists.txt +++ lib/Fuzzer/test/dfsan/CMakeLists.txt @@ -1,12 +1,14 @@ # These tests depend on both coverage and dfsan instrumentation. -set(CMAKE_CXX_FLAGS_RELEASE - "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all -fsanitize=dataflow") +# NOTE: Additional -fsanitize-coverage= flags come from HandleLLVMOptions.cmake +set(TEST_SANITIZE_FLAGS "-fno-sanitize=all" "-fsanitize=dataflow") foreach(Test ${DFSanTests}) add_executable(LLVMFuzzer-${Test}-DFSan ../${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test}-DFSan PRIVATE ${TEST_SANITIZE_FLAGS}) + llvm_append_linker_flag(LLVMFuzzer-${Test}-DFSan ${TEST_SANITIZE_FLAGS}) target_link_libraries(LLVMFuzzer-${Test}-DFSan LLVMFuzzer ) Index: lib/Fuzzer/test/trace-bb/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/trace-bb/CMakeLists.txt +++ lib/Fuzzer/test/trace-bb/CMakeLists.txt @@ -1,12 +1,13 @@ -# These tests are not instrumented with coverage. - -set(CMAKE_CXX_FLAGS_RELEASE - "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=edge,trace-bb") +set(TEST_SANITIZE_FLAGS "-fsanitize-coverage=edge,trace-bb") foreach(Test ${TraceBBTests}) add_executable(LLVMFuzzer-${Test}-TraceBB ../${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test}-TraceBB PRIVATE + ${TEST_SANITIZE_FLAGS} + ) + llvm_append_linker_flag(LLVMFuzzer-${Test}-TraceBB ${TEST_SANITIZE_FLAGS}) target_link_libraries(LLVMFuzzer-${Test}-TraceBB LLVMFuzzer ) Index: lib/Fuzzer/test/trace-pc/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -1,14 +1,19 @@ -# These tests are not instrumented with coverage. - -set(CMAKE_CXX_FLAGS_RELEASE - "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize-coverage=8bit-counters -fsanitize-coverage=trace-pc") +set(TEST_SANITIZE_FLAGS + "-fno-sanitize-coverage=8bit-counters" + "-fsanitize-coverage=trace-pc" +) foreach(Test ${TracePCTests}) add_executable(LLVMFuzzer-${Test}-TracePC ../${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test}-TracePC PRIVATE + ${TEST_SANITIZE_FLAGS} + ) + llvm_append_linker_flag(LLVMFuzzer-${Test}-TracePC + ${TEST_SANITIZE_FLAGS} + ) target_link_libraries(LLVMFuzzer-${Test}-TracePC LLVMFuzzer ) endforeach() - Index: lib/Fuzzer/test/ubsan/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/ubsan/CMakeLists.txt +++ lib/Fuzzer/test/ubsan/CMakeLists.txt @@ -1,12 +1,19 @@ # These tests are instrumented with ubsan in non-recovery mode. -set(CMAKE_CXX_FLAGS_RELEASE - "${LIBFUZZER_FLAGS_BASE} -O0 -fsanitize=undefined -fno-sanitize-recover=all") +# NOTE: Additional -fsanitize-coverage= flags come from HandleLLVMOptions.cmake +set(TEST_SANITIZE_FLAGS + "-fsanitize=undefined" + "-fno-sanitize-recover=all" +) foreach(Test ${UbsanTests}) add_executable(LLVMFuzzer-${Test}-Ubsan ../${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test}-Ubsan PRIVATE + ${TEST_SANITIZE_FLAGS} + ) + llvm_append_linker_flag(LLVMFuzzer-${Test}-Ubsan ${TEST_SANITIZE_FLAGS}) target_link_libraries(LLVMFuzzer-${Test}-Ubsan LLVMFuzzer ) Index: lib/Fuzzer/test/uninstrumented/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/uninstrumented/CMakeLists.txt +++ lib/Fuzzer/test/uninstrumented/CMakeLists.txt @@ -1,12 +1,20 @@ # These tests are not instrumented with coverage. -set(CMAKE_CXX_FLAGS_RELEASE - "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") +set(TEST_SANITIZE_FLAGS + "-fno-sanitize=all" + "-fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters" +) foreach(Test ${UninstrumentedTests}) add_executable(LLVMFuzzer-${Test}-Uninstrumented ../${Test}.cpp ) + target_compile_options(LLVMFuzzer-${Test}-Uninstrumented PRIVATE + ${TEST_SANITIZE_FLAGS} + ) + llvm_append_linker_flag(LLVMFuzzer-${Test}-Uninstrumented + ${TEST_SANITIZE_FLAGS} + ) target_link_libraries(LLVMFuzzer-${Test}-Uninstrumented LLVMFuzzer )