From 11a520f6793e21e0a8a9301f5ec4c28a48131b85 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sat, 28 Mar 2020 08:56:38 +0000 Subject: tests: Add fuzzing harness for functions/classes in random.h --- src/Makefile.test.include | 7 +++++++ src/random.h | 14 +++++++++----- src/test/fuzz/random.cpp | 31 +++++++++++++++++++++++++++++++ src/test/fuzz/util.h | 19 +++++++++++++++---- 4 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 src/test/fuzz/random.cpp (limited to 'src') diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c01c9fc52a..059876bec8 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -91,6 +91,7 @@ FUZZ_TARGETS = \ test/fuzz/psbt_input_deserialize \ test/fuzz/psbt_output_deserialize \ test/fuzz/pub_key_deserialize \ + test/fuzz/random \ test/fuzz/rolling_bloom_filter \ test/fuzz/script \ test/fuzz/script_deserialize \ @@ -819,6 +820,12 @@ test_fuzz_pub_key_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_pub_key_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_pub_key_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp +test_fuzz_random_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_random_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_random_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_random_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_random_SOURCES = $(FUZZ_SUITE) test/fuzz/random.cpp + test_fuzz_rolling_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_rolling_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_rolling_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/random.h b/src/random.h index 518a5cd3e3..4e4597cff6 100644 --- a/src/random.h +++ b/src/random.h @@ -103,7 +103,8 @@ void RandAddEvent(const uint32_t event_info) noexcept; * * This class is not thread-safe. */ -class FastRandomContext { +class FastRandomContext +{ private: bool requires_seed; ChaCha20 rng; @@ -155,7 +156,8 @@ public: } /** Generate a random (bits)-bit integer. */ - uint64_t randbits(int bits) noexcept { + uint64_t randbits(int bits) noexcept + { if (bits == 0) { return 0; } else if (bits > 32) { @@ -169,7 +171,9 @@ public: } } - /** Generate a random integer in the range [0..range). */ + /** Generate a random integer in the range [0..range). + * Precondition: range > 0. + */ uint64_t randrange(uint64_t range) noexcept { assert(range); @@ -210,7 +214,7 @@ public: * debug mode detects and panics on. This is a known issue, see * https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle */ -template +template void Shuffle(I first, I last, R&& rng) { while (first != last) { @@ -233,7 +237,7 @@ static const int NUM_OS_RANDOM_BYTES = 32; /** Get 32 bytes of system entropy. Do not use this in application code: use * GetStrongRandBytes instead. */ -void GetOSRand(unsigned char *ent32); +void GetOSRand(unsigned char* ent32); /** Check that OS randomness is available and returning the requested number * of bytes. diff --git a/src/test/fuzz/random.cpp b/src/test/fuzz/random.cpp new file mode 100644 index 0000000000..7df6594ad6 --- /dev/null +++ b/src/test/fuzz/random.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 +#include +#include +#include + +#include +#include +#include +#include + +void test_one_input(const std::vector& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; + (void)fast_random_context.rand64(); + (void)fast_random_context.randbits(fuzzed_data_provider.ConsumeIntegralInRange(0, 64)); + (void)fast_random_context.randrange(fuzzed_data_provider.ConsumeIntegralInRange(FastRandomContext::min() + 1, FastRandomContext::max())); + (void)fast_random_context.randbytes(fuzzed_data_provider.ConsumeIntegralInRange(0, 1024)); + (void)fast_random_context.rand32(); + (void)fast_random_context.rand256(); + (void)fast_random_context.randbool(); + (void)fast_random_context(); + + std::vector integrals = ConsumeRandomLengthIntegralVector(fuzzed_data_provider); + Shuffle(integrals.begin(), integrals.end(), fast_random_context); + std::shuffle(integrals.begin(), integrals.end(), fast_random_context); +} diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 10be2ebaf7..7004aff420 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -20,13 +20,13 @@ #include #include -NODISCARD inline std::vector ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, size_t max_length = 4096) noexcept +NODISCARD inline std::vector ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length); return {s.begin(), s.end()}; } -NODISCARD inline std::vector ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, size_t max_vector_size = 16, size_t max_string_length = 16) noexcept +NODISCARD inline std::vector ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept { const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange(0, max_vector_size); std::vector r; @@ -37,7 +37,18 @@ NODISCARD inline std::vector ConsumeRandomLengthStringVector(Fuzzed } template -NODISCARD inline Optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, size_t max_length = 4096) noexcept +NODISCARD inline std::vector ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept +{ + const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange(0, max_vector_size); + std::vector r; + for (size_t i = 0; i < n_elements; ++i) { + r.push_back(fuzzed_data_provider.ConsumeIntegral()); + } + return r; +} + +template +NODISCARD inline Optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { const std::vector buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION}; @@ -81,7 +92,7 @@ NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider } template -bool MultiplicationOverflow(T i, T j) +NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept { static_assert(std::is_integral::value, "Integral required."); if (std::numeric_limits::is_signed) { -- cgit v1.2.3