diff --git a/compiler-rt/lib/fuzzer/CMakeLists.txt b/compiler-rt/lib/fuzzer/CMakeLists.txt --- a/compiler-rt/lib/fuzzer/CMakeLists.txt +++ b/compiler-rt/lib/fuzzer/CMakeLists.txt @@ -170,7 +170,47 @@ partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX} ${arch}) partially_link_libcxx(fuzzer_interceptors ${LIBCXX_${arch}_PREFIX} ${arch}) partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch}) + if(NOT ${arch} MATCHES "i386") # i386 unsupported for .so version. + add_custom_command( + OUTPUT clang_rt.fuzzer_no_main-${arch}.so + DEPENDS clang_rt.fuzzer_no_main-${arch} + COMMAND ${CMAKE_CXX_COMPILER} ${EMULATION_ARGUMENT} -Wl,--whole-archive -rdynamic "$" -Wl,--no-whole-archive -shared -fPIC -o "$/libclang_rt.fuzzer_no_main-${arch}.so" + COMMENT "Building clang_rt.fuzzer_no_main-${arch}.so" + ) + get_compiler_rt_install_dir(${arch} install_dir) + install(FILES "$/libclang_rt.fuzzer_no_main-${arch}.so" + DESTINATION ${install_dir} + ) + add_custom_target( + clang_rt.fuzzer_no_main-${arch}-so ALL + DEPENDS clang_rt.fuzzer_no_main-${arch}.so + ) + endif() endforeach() +else() + +set(LIBFUZZER_SHARED_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) + +set(LIBFUZZER_SHARED_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}) +if (DARWIN) + list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lc++") +else() + list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lstdc++") +endif() +list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lm") +list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lpthread") + +# If we aren't statically linking libc++ into the fuzzer, we can build the shared object directly +add_compiler_rt_runtime(clang_rt.fuzzer_no_main + SHARED + OS ${FUZZER_SUPPORTED_OS} + ARCHS ${FUZZER_SUPPORTED_ARCH} + OBJECT_LIBS RTfuzzer + CFLAGS ${LIBFUZZER_CFLAGS} + LINK_FLAGS ${LIBFUZZER_SHARED_LINK_FLAGS} + LINK_LIBS ${LIBFUZZER_SHARED_LINK_LIBS} + PARENT_TARGET fuzzer) + endif() if(COMPILER_RT_INCLUDE_TESTS) diff --git a/llvm/docs/LibFuzzer.rst b/llvm/docs/LibFuzzer.rst --- a/llvm/docs/LibFuzzer.rst +++ b/llvm/docs/LibFuzzer.rst @@ -620,13 +620,18 @@ Using libFuzzer as a library ---------------------------- If the code being fuzzed must provide its own `main`, it's possible to -invoke libFuzzer as a library. Be sure to pass ``-fsanitize=fuzzer-no-link`` +invoke libFuzzer as a library. Static linking is available on all platforms +supported by libFuzzer; however, dynamic linking is not available on +certain platforms (notably 32-bit x86 Linux). + +When using libFuzzer as a library, be sure to pass ``-fsanitize=fuzzer-no-link`` during compilation, and link your binary against the no-main version of libFuzzer. On Linux installations, this is typically located at: .. code-block:: bash /usr/lib//lib/clang//lib/linux/libclang_rt.fuzzer_no_main-.a + /usr/lib//lib/clang//lib/linux/libclang_rt.fuzzer_no_main-.so If building libFuzzer from source, this is located at the following path in the build output directory: @@ -634,6 +639,7 @@ .. code-block:: bash lib/linux/libclang_rt.fuzzer_no_main-.a + lib/linux/libclang_rt.fuzzer_no_main-.so From here, the code can do whatever setup it requires, and when it's ready to start fuzzing, it can call `LLVMFuzzerRunDriver`, passing in the program @@ -645,8 +651,6 @@ extern "C" int LLVMFuzzerRunDriver(int *argc, char ***argv, int (*UserCb)(const uint8_t *Data, size_t Size)); - - Leaks -----