This change adds a CMake rule to produce shared object versions of libFuzzer (no-main). Unlike the static library versions, these shared libraries do not have a copy of libc++ statically linked in. Doing so is theoretically possible for x86-64 (via hacks); however, it is not possible for i386 because i386 does not suppot mixing position-independent and non-position-independent code in the same library.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Do we need a version for 32-bit at all?
Not having a private version of libc++ is likely to cause subtle stability issues.
(Matt, please help me with the review here)
Sticking just with x86_64 is possible; I actually have the code for that here, but it's a bit ugly:
https://reviews.llvm.org/differential/diff/281467/
However, what stability issues could dynamic linking cause? The change to privately link libc++ was only added in 2019, so things must have worked well before then:
https://github.com/llvm/llvm-project/commit/66c60d9d714bed88765c1575fbf57e7582fd27a3
I'm fine with whichever version you prefer.
If you don't need 32-bit .so, let's just have it in 64-bit version (and this fact documented)
However, what stability issues could dynamic linking cause? The change to privately link libc++ was only added in 2019, so things must have worked well before then:
https://github.com/llvm/llvm-project/commit/66c60d9d714bed88765c1575fbf57e7582fd27a3
Things didn't work well and we had a few workarounds, some were since reverted.
The problem with a non-private libc++ is that the common libc++ is instrumented for coverage.
Since libFuzzer itself uses libc++, the coverage instrumentation code is executed while inside libFuzzer,
screwing everything up.
I'm fine with whichever version you prefer.
When I patch this in locally and run ninja check-fuzzer, I get a linking error for both i386 and x86_64:
FAILED: lib/clang/12.0.0/lib/linux/libclang_rt.fuzzer_no_main-i386.so ... /usr/bin/ld: projects/compiler-rt/lib/fuzzer/CMakeFiles/RTfuzzer.i386.dir/FuzzerDriver.cpp.o: in function `fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned int))': /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create' /usr/bin/ld: /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create' /usr/bin/ld: projects/compiler-rt/lib/fuzzer/CMakeFiles/RTfuzzer.i386.dir/FuzzerFork.cpp.o: in function `fuzzer::FuzzWithFork(fuzzer::Random&, fuzzer::FuzzingOptions const&, std::vector<std::__cxx11::basic_stri ng<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::vector<std::__cxx11::basic_stri ng<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, int)': /usr/local/google/home/mascasa/code/llvm-project/compiler-rt/lib/fuzzer/FuzzerFork.cpp:(.text+0xd6d): undefined reference to `pthread_create' clang: error: linker command failed with exit code 1 (use -v to see invocation) [655/3462] Linking CXX shared library lib/clang/12.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.so FAILED: lib/clang/12.0.0/lib/linux/libclang_rt.fuzzer_no_main-x86_64.so ... /usr/bin/ld: projects/compiler-rt/lib/fuzzer/CMakeFiles/RTfuzzer.x86_64.dir/FuzzerDriver.cpp.o: in function `fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long))': /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create' /usr/bin/ld: /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create' /usr/bin/ld: /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create' /usr/bin/ld: projects/compiler-rt/lib/fuzzer/CMakeFiles/RTfuzzer.x86_64.dir/FuzzerFork.cpp.o: in function `fuzzer::FuzzWithFork(fuzzer::Random&, fuzzer::FuzzingOptions const&, std::vector<std::__cxx11::basic_st ring<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::vector<std::__cxx11::basic_st ring<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, int)': /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:130: undefined reference to `pthread_create'
Ian, can you please take a look?
So it looks like the bug in question was pre-existing, and this change just exposes it. Specifically, when building with Ninja instead of Makefiles, the code path for statically linking libc++ isn't actually hit. Rather, the fallthrough "normal" code path is hit. I've confirmed this by verifying that the assemblies produced before my change with Ninja still want regular libc++.
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
61 | Nit: Can we rename this to LIBFUZZER_SHARED_LINK_FLAGS and move it down next to the case where it is used? |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
192 | This is broken on non-Linux and non-Fuchsia architectures which don't have libstdc++, for example Darwin. Can you please fix or revert? |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
192 | Would it be sufficient to add the following? if (DARWIN) list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lc++") else() list(APPEND LIBFUZZER_SHARED_LINK_LIBS "-lstdc++") endif() Or are there more platforms that are missing libstdc++? |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
192 | Why is this particular line hardcoding some particular C++ STD implementation in the first place? |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
194 | This line was also failing on Android, where there is no pthreads library. |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
192 | Passing -stdlib=libc++ into the CFLAGS of the rule doesn't solve the problem. The .so links, but at runtime it complains about missing symbols like _ZTVN10cxxabiv120si_class_type_infoE. | |
192 | Added this in https://reviews.llvm.org/D85339. However, I don't have a Darwin machine to test with. |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
195 | This is too fragile, basically duplicates defaults from clang/lib/Driver/ToolChains |
compiler-rt/lib/fuzzer/CMakeLists.txt | ||
---|---|---|
195 | I don't suppose you have any suggestions? I don't even know why libstdc++ isn't being linked in automatically. |
Nit: Can we rename this to LIBFUZZER_SHARED_LINK_FLAGS and move it down next to the case where it is used?