Repository: bitcoin/bitcoin
File: src/test/fuzz/fuzz.cpp (C++)

Code before:
    if (should_exit) {
        std::exit(EXIT_SUCCESS);
    }
    if (const auto* env_fuzz{std::getenv("FUZZ")}) {
        // To allow for easier fuzz executable binary modification,
        static std::string g_copy{env_fuzz}; // create copy to avoid compiler optimizations, and
        g_fuzz_target = g_copy.c_str();      // strip string after the first null-char.
    } else {
        std::cerr << "Must select fuzz target with the FUZZ env var." << std::endl;
        std::cerr << "Hint: Set the PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 env var to see all compiled targets." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    const auto it = FuzzTargets().find(g_fuzz_target);
    if (it == FuzzTargets().end()) {
        std::cerr << "No fuzz target compiled for " << g_fuzz_target << "." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    if constexpr (!G_FUZZING) {
        std::cerr << "Must compile with -DBUILD_FOR_FUZZING=ON to execute a fuzz target." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    Assert(!g_test_one_input);
    g_test_one_input = &it->second.test_one_input;
    it->second.opts.init();

    ResetCoverageCounters();
}

#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
static bool read_stdin(std::vector<uint8_t>& data)
{
    std::istream::char_type buffer[1024];
    std::streamsize length;
    while ((std::cin.read(buffer, 1024), length = std::cin.gcount()) > 0) {
        data.insert(data.end(), buffer, buffer + length);
    }
    return length == 0;
}
#endif

#if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
static bool read_file(fs::path p, std::vector<uint8_t>& data)
{
    uint8_t buffer[1024];
    FILE* f = fsbridge::fopen(p, "rb");
    if (f == nullptr) return false;
    do {
        const size_t length = fread(buffer, sizeof(uint8_t), sizeof(buffer), f);
        if (ferror(f)) return false;
        data.insert(data.end(), buffer, buffer + length);
    } while (!feof(f));

Review comment (bug):
Is there a use-case for FUZZ_NONDETERMINISM? IIRC the goal of this change was to achieve fuzz determinism, so adding non-determinism could be left for a follow-up? I'd even argue that it may be better to not add at all, because it is such an edge case that no one will be using it. However, it existing, implies that reviewers will have to take it into account every time, which doesn't seem worth it.

If you remove it, you can also move the `assert(EnableFuzzDeterminism());` before `Assert(!g_test_one_input);`, so that it is executed unconditionally.

edit: nit: The `g_enable_dynamic_fuzz_determinism` could probably be a plain `bool` (without atomic).


Code after:
    }
    if (const auto* env_fuzz{std::getenv("FUZZ")}) {
        // To allow for easier fuzz executable binary modification,
        static std::string g_copy{env_fuzz}; // create copy to avoid compiler optimizations, and
        g_fuzz_target = g_copy.c_str();      // strip string after the first null-char.
    } else {
        std::cerr << "Must select fuzz target with the FUZZ env var." << std::endl;
        std::cerr << "Hint: Set the PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 env var to see all compiled targets." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    const auto it = FuzzTargets().find(g_fuzz_target);
    if (it == FuzzTargets().end()) {
        std::cerr << "No fuzz target compiled for " << g_fuzz_target << "." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    if constexpr (!G_FUZZING_BUILD && !G_ABORT_ON_FAILED_ASSUME) {
        std::cerr << "Must compile with -DBUILD_FOR_FUZZING=ON or in Debug mode to execute a fuzz target." << std::endl;
        std::exit(EXIT_FAILURE);
    }
    if (!EnableFuzzDeterminism()) {
        if (std::getenv("FUZZ_NONDETERMINISM")) {
            std::cerr << "Warning: FUZZ_NONDETERMINISM env var set, results may be inconsistent with fuzz build" << std::endl;
        } else {
            g_enable_dynamic_fuzz_determinism = true;
            assert(EnableFuzzDeterminism());
        }
    }
    Assert(!g_test_one_input);
    g_test_one_input = &it->second.test_one_input;
    it->second.opts.init();

    ResetCoverageCounters();
}

#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
static bool read_stdin(std::vector<uint8_t>& data)
{
    std::istream::char_type buffer[1024];
    std::streamsize length;
    while ((std::cin.read(buffer, 1024), length = std::cin.gcount()) > 0) {
        data.insert(data.end(), buffer, buffer + length);
    }
    return length == 0;
}
#endif

#if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
static bool read_file(fs::path p, std::vector<uint8_t>& data)
{
    uint8_t buffer[1024];
    FILE* f = fsbridge::fopen(p, "rb");