From f1282130cfeac789a5cd3e60ac236b9081445f34 Mon Sep 17 00:00:00 2001 From: "R. Elliott Childre" Date: Thu, 3 Jul 2025 10:25:31 -0400 Subject: [PATCH] Update vendored LibFuzzer to LLVM 20.x release Specifically: * Tag: `llvmorg-20.1.7` * Commit: `6146a88f60492b520a36f8f8f3231e15f3cc6082` Major changes: * Clarified behavior of `-max_len` option * Avoid UBSan faults in LibFuzzer by guarding `memcpy()` calls to check for valid size argument * Fix building LibFuzzer with `clang-cl` * Thread name setting logic for Fuchsia and Windows Full commit log: `git log --format=ref release/19.x..release/20.x -- 'compiler-rt/lib/fuzzer/'` ``` 091741a880c2 ([libfuzzer] Clarify -max_len behavior on bigger files (#123095), 2025-01-23) f9125ddc1faa (Revert "[libfuzzer] use timer_create() instead of setitimer() for linux" (#115811), 2024-11-11) 3b29a8a00809 ([libfuzzer] use timer_create() instead of setitimer() for linux (#110274), 2024-11-12) 5082acce4fd3 ([compiler-rt] Add custom libc++ workaround for CMake < 3.26, 2024-11-10) 87f4bc0acad6 ([compiler-rt] [fuzzer] Skip trying to set the thread name on MinGW (#115167), 2024-11-07) e7bad34475e2 ([compiler-rt] Use installed libc++(abi) for tests instead of build tree, 2024-11-06) a6fdfefbd04d ([compiler-rt] Include stdlib.h for exit() (#115025), 2024-11-05) d54953ef472b ([fuzzer] fix clang-cl build fuzzer lit test failure (#112339), 2024-10-17) b4130bee6bfd (Fix libFuzzer not building with pthreads on Windows (#109525), 2024-09-24) b32dc677325c (Revert "[compiler-rt][fuzzer] SetThreadName build fix for Mingwin attempt (#106902)", 2024-09-02) 7c4cffd9d8be ([compiler-rt][fuzzer] SetThreadName build fix for Mingwin attempt (#106902), 2024-09-01) f47966b1de45 ([compiler-rt] Reland "SetThreadName implementation for Fuchsia" (#105179), 2024-08-21) ddaa8284f5b4 (Revert "[compiler-rt][fuzzer] implements SetThreadName for fuchsia." (#105162), 2024-08-20) 31cc4ccdea92 ([compiler-rt][fuzzer] implements SetThreadName for fuchsia. (#99953), 2024-08-20) bde4ffe75214 (Don't pass null pointers to memcmp and memcpy in libFuzzer (#96775), 2024-08-13) 7202fe582931 ([compiler-rt] Silence warnings, 2024-08-11) ``` --- CHANGELOG.md | 2 +- libfuzzer/CMakeLists.txt | 6 ++--- libfuzzer/FuzzerDictionary.h | 4 +++- libfuzzer/FuzzerExtFunctionsWindows.cpp | 29 +++++++++++++------------ libfuzzer/FuzzerFlags.def | 5 +++-- libfuzzer/FuzzerLoop.cpp | 7 +++++- libfuzzer/FuzzerUtilFuchsia.cpp | 6 ++++- libfuzzer/FuzzerUtilWindows.cpp | 13 ++++++----- libfuzzer/tests/CMakeLists.txt | 2 +- update-libfuzzer.sh | 2 +- 10 files changed, 45 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2571d8..763291a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Released YYYY-MM-DD. ### Changed -* TODO (or remove section if none) +* Updated to `libFuzzer` commit `6146a88f6049` (`release/20.x`). ### Deprecated diff --git a/libfuzzer/CMakeLists.txt b/libfuzzer/CMakeLists.txt index fb5adf1..6db2461 100644 --- a/libfuzzer/CMakeLists.txt +++ b/libfuzzer/CMakeLists.txt @@ -166,11 +166,11 @@ if(OS_NAME MATCHES "Android|Linux|Fuchsia" AND -DLIBCXX_ABI_NAMESPACE=__Fuzzer -DLIBCXX_ENABLE_EXCEPTIONS=OFF) target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) - add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build) + add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-install-cmake326-workaround) target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) - add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build) + add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-install-cmake326-workaround) target_compile_options(RTfuzzer_interceptors.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) - add_dependencies(RTfuzzer_interceptors.${arch} libcxx_fuzzer_${arch}-build) + add_dependencies(RTfuzzer_interceptors.${arch} libcxx_fuzzer_${arch}-install-cmake326-workaround) 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}) diff --git a/libfuzzer/FuzzerDictionary.h b/libfuzzer/FuzzerDictionary.h index 48f063c..64eb35c 100644 --- a/libfuzzer/FuzzerDictionary.h +++ b/libfuzzer/FuzzerDictionary.h @@ -29,7 +29,9 @@ template class FixedWord { static_assert(kMaxSizeT <= std::numeric_limits::max(), "FixedWord::kMaxSizeT cannot fit in a uint8_t."); assert(S <= kMaxSize); - memcpy(Data, B, S); + // memcpy cannot take null pointer arguments even if Size is 0. + if (S) + memcpy(Data, B, S); Size = static_cast(S); } diff --git a/libfuzzer/FuzzerExtFunctionsWindows.cpp b/libfuzzer/FuzzerExtFunctionsWindows.cpp index 688bad1..566820a 100644 --- a/libfuzzer/FuzzerExtFunctionsWindows.cpp +++ b/libfuzzer/FuzzerExtFunctionsWindows.cpp @@ -14,6 +14,7 @@ #include "FuzzerExtFunctions.h" #include "FuzzerIO.h" +#include using namespace fuzzer; @@ -22,6 +23,11 @@ using namespace fuzzer; #define STRINGIFY(A) STRINGIFY_(A) #if LIBFUZZER_MSVC +#define GET_FUNCTION_ADDRESS(fn) &fn +#else +#define GET_FUNCTION_ADDRESS(fn) __builtin_function_start(fn) +#endif // LIBFUZER_MSVC + // Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h #if defined(_M_IX86) || defined(__i386__) #define WIN_SYM_PREFIX "_" @@ -31,17 +37,9 @@ using namespace fuzzer; // Declare external functions as having alternativenames, so that we can // determine if they are not defined. -#define EXTERNAL_FUNC(Name, Default) \ - __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \ +#define EXTERNAL_FUNC(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \ Name) "=" WIN_SYM_PREFIX STRINGIFY(Default))) -#else -// Declare external functions as weak to allow them to default to a specified -// function if not defined explicitly. We must use weak symbols because clang's -// support for alternatename is not 100%, see -// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details. -#define EXTERNAL_FUNC(Name, Default) \ - __attribute__((weak, alias(STRINGIFY(Default)))) -#endif // LIBFUZZER_MSVC extern "C" { #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ @@ -57,20 +55,23 @@ extern "C" { } template -static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) { +static T *GetFnPtr(void *Fun, void *FunDef, const char *FnName, + bool WarnIfMissing) { if (Fun == FunDef) { if (WarnIfMissing) Printf("WARNING: Failed to find function \"%s\".\n", FnName); return nullptr; } - return Fun; + return (T *)Fun; } namespace fuzzer { ExternalFunctions::ExternalFunctions() { -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - this->NAME = GetFnPtr(::NAME, ::NAME##Def, #NAME, WARN); +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + this->NAME = GetFnPtr(GET_FUNCTION_ADDRESS(::NAME), \ + GET_FUNCTION_ADDRESS(::NAME##Def), \ + #NAME, WARN); #include "FuzzerExtFunctions.def" diff --git a/libfuzzer/FuzzerFlags.def b/libfuzzer/FuzzerFlags.def index fc3b3aa..b88458a 100644 --- a/libfuzzer/FuzzerFlags.def +++ b/libfuzzer/FuzzerFlags.def @@ -14,8 +14,9 @@ FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") FUZZER_FLAG_INT(runs, -1, "Number of individual test runs (-1 for infinite runs).") FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " - "If 0, libFuzzer tries to guess a good value based on the corpus " - "and reports it. ") + "Contents of corpus files are going to be truncated to this value. " + "If 0, libFuzzer tries to guess a good value based on the corpus " + "and reports it.") FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, " "then try larger inputs over time. Specifies the rate at which the length " "limit is increased (smaller == faster). If 0, immediately try inputs with " diff --git a/libfuzzer/FuzzerLoop.cpp b/libfuzzer/FuzzerLoop.cpp index 935dd23..6f415dd 100644 --- a/libfuzzer/FuzzerLoop.cpp +++ b/libfuzzer/FuzzerLoop.cpp @@ -579,6 +579,9 @@ void Fuzzer::CrashOnOverwrittenData() { // Compare two arrays, but not all bytes if the arrays are large. static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { const size_t Limit = 64; + // memcmp cannot take null pointer arguments even if Size is 0. + if (!Size) + return true; if (Size <= 64) return !memcmp(A, B, Size); // Compare first and last Limit/2 bytes. @@ -596,7 +599,9 @@ ATTRIBUTE_NOINLINE bool Fuzzer::ExecuteCallback(const uint8_t *Data, // We copy the contents of Unit into a separate heap buffer // so that we reliably find buffer overflows in it. uint8_t *DataCopy = new uint8_t[Size]; - memcpy(DataCopy, Data, Size); + // memcpy cannot take null pointer arguments even if Size is 0. + if (Size) + memcpy(DataCopy, Data, Size); if (EF->__msan_unpoison) EF->__msan_unpoison(DataCopy, Size); if (EF->__msan_unpoison_param) diff --git a/libfuzzer/FuzzerUtilFuchsia.cpp b/libfuzzer/FuzzerUtilFuchsia.cpp index fe79e19..735d155 100644 --- a/libfuzzer/FuzzerUtilFuchsia.cpp +++ b/libfuzzer/FuzzerUtilFuchsia.cpp @@ -607,7 +607,11 @@ size_t PageSize() { } void SetThreadName(std::thread &thread, const std::string &name) { - // TODO ? + if (zx_status_t s = zx_object_set_property( + thread.native_handle(), ZX_PROP_NAME, name.data(), name.size()); + s != ZX_OK) + Printf("SetThreadName for name %s failed: %s", name.c_str(), + zx_status_get_string(s)); } } // namespace fuzzer diff --git a/libfuzzer/FuzzerUtilWindows.cpp b/libfuzzer/FuzzerUtilWindows.cpp index 73eea07..2db2ea9 100644 --- a/libfuzzer/FuzzerUtilWindows.cpp +++ b/libfuzzer/FuzzerUtilWindows.cpp @@ -239,14 +239,15 @@ size_t PageSize() { } void SetThreadName(std::thread &thread, const std::string &name) { -#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) || \ - defined(_GLIBCXX_GCC_GTHR_POSIX_H) - (void)pthread_setname_np(thread.native_handle(), name.c_str()); -#else +#ifndef __MINGW32__ + // Not setting the thread name in MinGW environments. MinGW C++ standard + // libraries can either use native Windows threads or pthreads, so we + // don't know with certainty what kind of thread handle we're getting + // from thread.native_handle() here. typedef HRESULT(WINAPI * proc)(HANDLE, PCWSTR); HMODULE kbase = GetModuleHandleA("KernelBase.dll"); - proc ThreadNameProc = - reinterpret_cast(GetProcAddress(kbase, "SetThreadDescription")); + proc ThreadNameProc = reinterpret_cast( + (void *)GetProcAddress(kbase, "SetThreadDescription")); if (ThreadNameProc) { std::wstring buf; auto sz = MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, nullptr, 0); diff --git a/libfuzzer/tests/CMakeLists.txt b/libfuzzer/tests/CMakeLists.txt index 5086c03..adfae3d 100644 --- a/libfuzzer/tests/CMakeLists.txt +++ b/libfuzzer/tests/CMakeLists.txt @@ -64,7 +64,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH) 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_DEPS libcxx_fuzzer_${arch}-install-cmake326-workaround ${libfuzzer_headers}) set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1) set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a) endif() diff --git a/update-libfuzzer.sh b/update-libfuzzer.sh index 0e1e6dd..059a273 100755 --- a/update-libfuzzer.sh +++ b/update-libfuzzer.sh @@ -8,7 +8,7 @@ set -ex # The LLVM commit from which we are vendoring libfuzzer. This must be a commit # hash from https://github.com/llvm/llvm-project -COMMIT=ab51eccf88f5321e7c60591c5546b254b6afab99 +COMMIT=6146a88f60492b520a36f8f8f3231e15f3cc6082 cd "$(dirname $0)" project_dir="$(pwd)"