aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2020-07-18 09:00:39 +0200
committerMarcoFalke <falke.marco@gmail.com>2020-07-18 09:24:58 +0200
commit090d87716074434bdc6c7656ec44d049197a793a (patch)
tree9c82d8c1497b61e1abbd662c972f1467c05b6854 /src
parentfd59670642f511523570607b752ae409b5e04e7d (diff)
parentad6c34881dc125c973b6b9ba1daa999d3141b1ae (diff)
Merge #19143: tests: Add fuzzing harnesses for CAutoFile, CBufferedFile, LoadExternalBlockFile and other FILE* consumers
ad6c34881dc125c973b6b9ba1daa999d3141b1ae tests: Add fuzzing harness for CBlockPolicyEstimator::{Read,Write} (policy/fees.h) (practicalswift) 614e0807a8137d82832aea45e4864b424f71f698 tests: Add fuzzing harness for CBufferedFile::{SetPos,GetPos,GetType,GetVersion} (stream.h) (practicalswift) 7bcc71e5f8cdfd8ba1411c799c0726f503e52343 tests: Add fuzzing harness for LoadExternalBlockFile(...) (validation.h) (practicalswift) 98233760305a36acbd41d76aeebeada1340f6367 tests: Add fuzzing harness for CBufferedFile (streams.h) (practicalswift) f3aa659be676a4dd0c20fe6c5cb4acd7a5b38b76 tests: Add fuzzing harness for CAutoFile (streams.h) (practicalswift) e507c0799d759355dd0cfbe83449f0f767a7264e tests: Add serialization/deserialization fuzzing helpers WriteToStream(…)/ReadFromStream(…) (practicalswift) e48094a506ad031d211b9dfe7639d8b3a2239788 tests: Add FuzzedAutoFileProvider which provides a CAutoFile interface to FuzzedDataProvider (practicalswift) 9dbcd6854ca05a9bd1e9a5e1222dac1758048231 tests: Add FuzzedFileProvider which provides a FILE* interface to FuzzedDataProvider using fopencookie (practicalswift) Pull request description: Add fuzzing harnesses for `CAutoFile`, `CBufferedFile`, `LoadExternalBlockFile` and other `FILE*` consumers: * Add `FuzzedFileProvider` which provides a `FILE*` interface to `FuzzedDataProvider` using `fopencookie` * Add `FuzzedAutoFileProvider` which provides a `CAutoFile` interface to `FuzzedDataProvider` * Add serialization/deserialization fuzzing helpers `WriteToStream(…)`/`ReadFromStream(…)` * Add fuzzing harness for `CAutoFile` (`streams.h`) * Add fuzzing harness for `CBufferedFile` (`streams.h`) * Add fuzzing harness for `LoadExternalBlockFile(...)` (`validation.h`) * Add fuzzing harness for `CBlockPolicyEstimator::Read` and `CBlockPolicyEstimator::Write` (`policy/fees.h`) See [`doc/fuzzing.md`](https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md) for information on how to fuzz Bitcoin Core. Don't forget to contribute any coverage increasing inputs you find to the [Bitcoin Core fuzzing corpus repo](https://github.com/bitcoin-core/qa-assets). Happy fuzzing :) ACKs for top commit: Crypt-iQ: Tested ACK ad6c348 Tree-SHA512: a38e142608218496796a527d7e59b74e30279a2815450408b7c27a76ed600cebc6b88491e831665a0639671e2d212453fcdca558500bbadbeb32b267751f8f72
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include28
-rw-r--r--src/test/fuzz/autofile.cpp72
-rw-r--r--src/test/fuzz/buffered_file.cpp78
-rw-r--r--src/test/fuzz/load_external_block_file.cpp31
-rw-r--r--src/test/fuzz/policy_estimator.cpp11
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp28
-rw-r--r--src/test/fuzz/util.h206
7 files changed, 454 insertions, 0 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 3b51503948..637d1d2f6e 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -10,6 +10,7 @@ FUZZ_TARGETS = \
test/fuzz/addrman_deserialize \
test/fuzz/asmap \
test/fuzz/asmap_direct \
+ test/fuzz/autofile \
test/fuzz/banentry_deserialize \
test/fuzz/banman \
test/fuzz/base_encode_decode \
@@ -29,6 +30,7 @@ FUZZ_TARGETS = \
test/fuzz/blockundo_deserialize \
test/fuzz/bloom_filter \
test/fuzz/bloomfilter_deserialize \
+ test/fuzz/buffered_file \
test/fuzz/chain \
test/fuzz/checkqueue \
test/fuzz/coins_deserialize \
@@ -61,6 +63,7 @@ FUZZ_TARGETS = \
test/fuzz/key_io \
test/fuzz/key_origin_info_deserialize \
test/fuzz/kitchen_sink \
+ test/fuzz/load_external_block_file \
test/fuzz/locale \
test/fuzz/merkle_block_deserialize \
test/fuzz/merkleblock \
@@ -80,6 +83,7 @@ FUZZ_TARGETS = \
test/fuzz/partial_merkle_tree_deserialize \
test/fuzz/partially_signed_transaction_deserialize \
test/fuzz/policy_estimator \
+ test/fuzz/policy_estimator_io \
test/fuzz/pow \
test/fuzz/prefilled_transaction_deserialize \
test/fuzz/prevector \
@@ -356,6 +360,12 @@ test_fuzz_asmap_direct_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_asmap_direct_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_asmap_direct_SOURCES = test/fuzz/asmap_direct.cpp
+test_fuzz_autofile_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_autofile_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_autofile_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_autofile_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_autofile_SOURCES = test/fuzz/autofile.cpp
+
test_fuzz_banentry_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBANENTRY_DESERIALIZE=1
test_fuzz_banentry_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_banentry_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
@@ -470,6 +480,12 @@ test_fuzz_bloomfilter_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_bloomfilter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_bloomfilter_deserialize_SOURCES = test/fuzz/deserialize.cpp
+test_fuzz_buffered_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_buffered_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_buffered_file_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_buffered_file_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_buffered_file_SOURCES = test/fuzz/buffered_file.cpp
+
test_fuzz_chain_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_chain_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_chain_LDADD = $(FUZZ_SUITE_LD_COMMON)
@@ -662,6 +678,12 @@ test_fuzz_kitchen_sink_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_kitchen_sink_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_kitchen_sink_SOURCES = test/fuzz/kitchen_sink.cpp
+test_fuzz_load_external_block_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_load_external_block_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_load_external_block_file_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_load_external_block_file_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_load_external_block_file_SOURCES = test/fuzz/load_external_block_file.cpp
+
test_fuzz_locale_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON)
@@ -782,6 +804,12 @@ test_fuzz_policy_estimator_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_policy_estimator_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_policy_estimator_SOURCES = test/fuzz/policy_estimator.cpp
+test_fuzz_policy_estimator_io_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_policy_estimator_io_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_policy_estimator_io_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_policy_estimator_io_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_policy_estimator_io_SOURCES = test/fuzz/policy_estimator_io.cpp
+
test_fuzz_pow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_pow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_pow_LDADD = $(FUZZ_SUITE_LD_COMMON)
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
new file mode 100644
index 0000000000..7ea0bdd2a7
--- /dev/null
+++ b/src/test/fuzz/autofile.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <optional.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <array>
+#include <cstdint>
+#include <iostream>
+#include <optional>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
+ CAutoFile auto_file = fuzzed_auto_file_provider.open();
+ while (fuzzed_data_provider.ConsumeBool()) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
+ case 0: {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ break;
+ }
+ case 1: {
+ const std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ break;
+ }
+ case 2: {
+ try {
+ auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ break;
+ }
+ case 3: {
+ auto_file.fclose();
+ break;
+ }
+ case 4: {
+ ReadFromStream(fuzzed_data_provider, auto_file);
+ break;
+ }
+ case 5: {
+ WriteToStream(fuzzed_data_provider, auto_file);
+ break;
+ }
+ }
+ }
+ (void)auto_file.Get();
+ (void)auto_file.GetType();
+ (void)auto_file.GetVersion();
+ (void)auto_file.IsNull();
+ if (fuzzed_data_provider.ConsumeBool()) {
+ FILE* f = auto_file.release();
+ if (f != nullptr) {
+ fclose(f);
+ }
+ }
+}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
new file mode 100644
index 0000000000..6bbd13eb5c
--- /dev/null
+++ b/src/test/fuzz/buffered_file.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <optional.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <array>
+#include <cstdint>
+#include <iostream>
+#include <optional>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+ std::optional<CBufferedFile> opt_buffered_file;
+ FILE* fuzzed_file = fuzzed_file_provider.open();
+ try {
+ opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<int>());
+ } catch (const std::ios_base::failure&) {
+ if (fuzzed_file != nullptr) {
+ fclose(fuzzed_file);
+ }
+ }
+ if (opt_buffered_file && fuzzed_file != nullptr) {
+ bool setpos_fail = false;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
+ case 0: {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ break;
+ }
+ case 1: {
+ opt_buffered_file->Seek(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ break;
+ }
+ case 2: {
+ opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ break;
+ }
+ case 3: {
+ if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
+ setpos_fail = true;
+ }
+ break;
+ }
+ case 4: {
+ if (setpos_fail) {
+ // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop.
+ break;
+ }
+ try {
+ opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>());
+ } catch (const std::ios_base::failure&) {
+ }
+ break;
+ }
+ case 5: {
+ ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
+ break;
+ }
+ }
+ }
+ opt_buffered_file->GetPos();
+ opt_buffered_file->GetType();
+ opt_buffered_file->GetVersion();
+ }
+}
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
new file mode 100644
index 0000000000..d9de9d9866
--- /dev/null
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <chainparams.h>
+#include <flatfile.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <validation.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+ FILE* fuzzed_block_file = fuzzed_file_provider.open();
+ if (fuzzed_block_file == nullptr) {
+ return;
+ }
+ FlatFilePos flat_file_pos;
+ LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr);
+}
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 1cbf9b347f..6c94a47f3c 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -14,6 +14,11 @@
#include <string>
#include <vector>
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
@@ -66,4 +71,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
(void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
}
+ {
+ FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
+ CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ block_policy_estimator.Write(fuzzed_auto_file);
+ block_policy_estimator.Read(fuzzed_auto_file);
+ }
}
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
new file mode 100644
index 0000000000..0edcf201c7
--- /dev/null
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -0,0 +1,28 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <policy/fees.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
+ CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ // Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
+ static CBlockPolicyEstimator block_policy_estimator;
+ if (block_policy_estimator.Read(fuzzed_auto_file)) {
+ block_policy_estimator.Write(fuzzed_auto_file);
+ }
+}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 8cf91ef940..148610c04d 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -27,6 +27,7 @@
#include <algorithm>
#include <cstdint>
+#include <cstdio>
#include <optional>
#include <string>
#include <vector>
@@ -264,4 +265,209 @@ void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
}
+class FuzzedFileProvider
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+ int64_t m_offset = 0;
+
+public:
+ FuzzedFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
+ {
+ }
+
+ FILE* open()
+ {
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return nullptr;
+ }
+ std::string mode;
+ switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
+ case 0: {
+ mode = "r";
+ break;
+ }
+ case 1: {
+ mode = "r+";
+ break;
+ }
+ case 2: {
+ mode = "w";
+ break;
+ }
+ case 3: {
+ mode = "w+";
+ break;
+ }
+ case 4: {
+ mode = "a";
+ break;
+ }
+ case 5: {
+ mode = "a+";
+ break;
+ }
+ }
+#ifdef _GNU_SOURCE
+ const cookie_io_functions_t io_hooks = {
+ FuzzedFileProvider::read,
+ FuzzedFileProvider::write,
+ FuzzedFileProvider::seek,
+ FuzzedFileProvider::close,
+ };
+ return fopencookie(this, mode.c_str(), io_hooks);
+#else
+ (void)mode;
+ return nullptr;
+#endif
+ }
+
+ static ssize_t read(void* cookie, char* buf, size_t size)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ }
+ const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
+ if (random_bytes.empty()) {
+ return 0;
+ }
+ std::memcpy(buf, random_bytes.data(), random_bytes.size());
+ if (AdditionOverflow((uint64_t)fuzzed_file->m_offset, random_bytes.size())) {
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ }
+ fuzzed_file->m_offset += random_bytes.size();
+ return random_bytes.size();
+ }
+
+ static ssize_t write(void* cookie, const char* buf, size_t size)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
+ if (AdditionOverflow(fuzzed_file->m_offset, n)) {
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ }
+ fuzzed_file->m_offset += n;
+ return n;
+ }
+
+ static int seek(void* cookie, int64_t* offset, int whence)
+ {
+ assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ int64_t new_offset = 0;
+ if (whence == SEEK_SET) {
+ new_offset = *offset;
+ } else if (whence == SEEK_CUR) {
+ if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
+ return -1;
+ }
+ new_offset = fuzzed_file->m_offset + *offset;
+ }
+ if (new_offset < 0) {
+ return -1;
+ }
+ fuzzed_file->m_offset = new_offset;
+ *offset = new_offset;
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
+ }
+
+ static int close(void* cookie)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
+ }
+};
+
+NODISCARD inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {fuzzed_data_provider};
+}
+
+class FuzzedAutoFileProvider
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+ FuzzedFileProvider m_fuzzed_file_provider;
+
+public:
+ FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}, m_fuzzed_file_provider{fuzzed_data_provider}
+ {
+ }
+
+ CAutoFile open()
+ {
+ return {m_fuzzed_file_provider.open(), m_fuzzed_data_provider.ConsumeIntegral<int>(), m_fuzzed_data_provider.ConsumeIntegral<int>()};
+ }
+};
+
+NODISCARD inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {fuzzed_data_provider};
+}
+
+#define WRITE_TO_STREAM_CASE(id, type, consume) \
+ case id: { \
+ type o = consume; \
+ stream << o; \
+ break; \
+ }
+template <typename Stream>
+void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
+{
+ while (fuzzed_data_provider.ConsumeBool()) {
+ try {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
+ WRITE_TO_STREAM_CASE(0, bool, fuzzed_data_provider.ConsumeBool())
+ WRITE_TO_STREAM_CASE(1, char, fuzzed_data_provider.ConsumeIntegral<char>())
+ WRITE_TO_STREAM_CASE(2, int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>())
+ WRITE_TO_STREAM_CASE(3, uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>())
+ WRITE_TO_STREAM_CASE(4, int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>())
+ WRITE_TO_STREAM_CASE(5, uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>())
+ WRITE_TO_STREAM_CASE(6, int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>())
+ WRITE_TO_STREAM_CASE(7, uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>())
+ WRITE_TO_STREAM_CASE(8, int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>())
+ WRITE_TO_STREAM_CASE(9, uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>())
+ WRITE_TO_STREAM_CASE(10, float, fuzzed_data_provider.ConsumeFloatingPoint<float>())
+ WRITE_TO_STREAM_CASE(11, double, fuzzed_data_provider.ConsumeFloatingPoint<double>())
+ WRITE_TO_STREAM_CASE(12, std::string, fuzzed_data_provider.ConsumeRandomLengthString(32))
+ WRITE_TO_STREAM_CASE(13, std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider))
+ }
+ } catch (const std::ios_base::failure&) {
+ break;
+ }
+ }
+}
+
+#define READ_FROM_STREAM_CASE(id, type) \
+ case id: { \
+ type o; \
+ stream >> o; \
+ break; \
+ }
+template <typename Stream>
+void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
+{
+ while (fuzzed_data_provider.ConsumeBool()) {
+ try {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
+ READ_FROM_STREAM_CASE(0, bool)
+ READ_FROM_STREAM_CASE(1, char)
+ READ_FROM_STREAM_CASE(2, int8_t)
+ READ_FROM_STREAM_CASE(3, uint8_t)
+ READ_FROM_STREAM_CASE(4, int16_t)
+ READ_FROM_STREAM_CASE(5, uint16_t)
+ READ_FROM_STREAM_CASE(6, int32_t)
+ READ_FROM_STREAM_CASE(7, uint32_t)
+ READ_FROM_STREAM_CASE(8, int64_t)
+ READ_FROM_STREAM_CASE(9, uint64_t)
+ READ_FROM_STREAM_CASE(10, float)
+ READ_FROM_STREAM_CASE(11, double)
+ READ_FROM_STREAM_CASE(12, std::string)
+ READ_FROM_STREAM_CASE(13, std::vector<char>)
+ }
+ } catch (const std::ios_base::failure&) {
+ break;
+ }
+ }
+}
+
#endif // BITCOIN_TEST_FUZZ_UTIL_H