diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,10 @@ # Allow usage of sanitizers by setting ECM_ENABLE_SANITIZERS if(ENABLE_SANITIZERS) set(ECM_ENABLE_SANITIZERS ${ENABLE_SANITIZERS}) + # Handle the fuzzer sanitizer here. Because we don't want it to apply to any + # executable, remove it from the ECM list and apply only on desired targets. + list(REMOVE_ITEM ECM_ENABLE_SANITIZERS "fuzzer") + find_package(ECM NO_MODULE) if(ECM_MODULE_PATH) list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -188,3 +188,7 @@ test_bitcoin_fuzzy.cpp ) target_link_libraries(test_bitcoin_fuzzy server) +if("fuzzer" IN_LIST ENABLE_SANITIZERS) + target_compile_options(test_bitcoin_fuzzy PRIVATE -fsanitize=fuzzer) + target_link_libraries(test_bitcoin_fuzzy -fsanitize=fuzzer) +endif() diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp --- a/src/test/test_bitcoin_fuzzy.cpp +++ b/src/test/test_bitcoin_fuzzy.cpp @@ -52,8 +52,8 @@ TEST_ID_END }; -static bool read_stdin(std::vector &data) { - char buffer[1024]; +static bool read_stdin(std::vector &data) { + uint8_t buffer[1024]; ssize_t length = 0; while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) { data.insert(data.end(), buffer, buffer + length); @@ -63,10 +63,7 @@ return length == 0; } -int do_fuzz() { - std::vector buffer; - if (!read_stdin(buffer)) return 0; - +static int test_one_input(std::vector buffer) { if (buffer.size() < sizeof(uint32_t)) return 0; uint32_t test_id = 0xffffffff; @@ -281,8 +278,32 @@ return 0; } +static std::unique_ptr globalVerifyHandle; +void initialize() { + globalVerifyHandle = + std::unique_ptr(new ECCVerifyHandle()); +} + +// This function is used by libFuzzer +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + test_one_input(std::vector(data, data + size)); + return 0; +} + +// This function is used by libFuzzer +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + initialize(); + return 0; +} + +// Disabled under WIN32 due to clash with Cygwin's WinMain. +#ifndef WIN32 +// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides +// the main(...) function. +__attribute__((weak)) +#endif int main(int argc, char **argv) { - ECCVerifyHandle globalVerifyHandle; + initialize(); #ifdef __AFL_INIT // Enable AFL deferred forkserver mode. Requires compilation using // afl-clang-fast++. See fuzzing.md for details. @@ -292,11 +313,20 @@ #ifdef __AFL_LOOP // Enable AFL persistent mode. Requires compilation using afl-clang-fast++. // See fuzzing.md for details. + int ret = 0; while (__AFL_LOOP(1000)) { - do_fuzz(); + std::vector buffer; + if (!read_stdin(buffer)) { + continue; + } + ret = test_one_input(buffer); } - return 0; + return ret; #else - return do_fuzz(); + std::vector buffer; + if (!read_stdin(buffer)) { + return 0; + } + return test_one_input(buffer); #endif }