LCOV - code coverage report
Current view: top level - src/test/fuzz - util.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 36 151 23.8 %
Date: 2023-09-26 12:08:55 Functions: 6 157 3.8 %

          Line data    Source code
       1             : // Copyright (c) 2009-2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #ifndef BITCOIN_TEST_FUZZ_UTIL_H
       6             : #define BITCOIN_TEST_FUZZ_UTIL_H
       7             : 
       8             : #include <addresstype.h>
       9             : #include <arith_uint256.h>
      10             : #include <coins.h>
      11             : #include <compat/compat.h>
      12             : #include <consensus/amount.h>
      13             : #include <consensus/consensus.h>
      14             : #include <key.h>
      15             : #include <merkleblock.h>
      16             : #include <primitives/transaction.h>
      17             : #include <script/script.h>
      18             : #include <serialize.h>
      19             : #include <streams.h>
      20             : #include <test/fuzz/FuzzedDataProvider.h>
      21             : #include <test/fuzz/fuzz.h>
      22             : #include <uint256.h>
      23             : #include <version.h>
      24             : 
      25             : #include <algorithm>
      26             : #include <array>
      27             : #include <cstdint>
      28             : #include <cstdio>
      29             : #include <optional>
      30             : #include <string>
      31             : #include <vector>
      32             : 
      33             : class PeerManager;
      34             : 
      35             : template <typename... Callables>
      36      188773 : size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
      37             : {
      38      188773 :     constexpr size_t call_size{sizeof...(callables)};
      39             :     static_assert(call_size >= 1);
      40      188773 :     const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)};
      41             : 
      42      188773 :     size_t i{0};
      43      188773 :     ((i++ == call_index ? callables() : void()), ...);
      44      188773 :     return call_size;
      45             : }
      46             : 
      47             : template <typename Collection>
      48        2058 : auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
      49             : {
      50        2058 :     auto sz{col.size()};
      51        2058 :     assert(sz >= 1);
      52        2058 :     auto it = col.begin();
      53        2058 :     std::advance(it, fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
      54        2058 :     return *it;
      55             : }
      56             : 
      57             : template<typename B = uint8_t>
      58       33080 : [[nodiscard]] inline std::vector<B> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
      59             : {
      60             :     static_assert(sizeof(B) == 1);
      61       66160 :     const std::string s = max_length ?
      62        3377 :                               fuzzed_data_provider.ConsumeRandomLengthString(*max_length) :
      63       29703 :                               fuzzed_data_provider.ConsumeRandomLengthString();
      64       33080 :     std::vector<B> ret(s.size());
      65       33080 :     std::copy(s.begin(), s.end(), reinterpret_cast<char*>(ret.data()));
      66       33080 :     return ret;
      67       33080 : }
      68             : 
      69           0 : [[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
      70             : {
      71           0 :     return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
      72             : }
      73             : 
      74           0 : [[nodiscard]] inline DataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
      75             : {
      76           0 :     return DataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
      77             : }
      78             : 
      79           0 : [[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
      80             : {
      81           0 :     const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
      82           0 :     std::vector<std::string> r;
      83           0 :     for (size_t i = 0; i < n_elements; ++i) {
      84           0 :         r.push_back(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
      85           0 :     }
      86           0 :     return r;
      87           0 : }
      88             : 
      89             : template <typename T>
      90           0 : [[nodiscard]] inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
      91             : {
      92           0 :     const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
      93           0 :     std::vector<T> r;
      94           0 :     for (size_t i = 0; i < n_elements; ++i) {
      95           0 :         r.push_back(fuzzed_data_provider.ConsumeIntegral<T>());
      96           0 :     }
      97           0 :     return r;
      98           0 : }
      99             : 
     100             : template <typename P>
     101             : [[nodiscard]] P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept;
     102             : 
     103             : template <typename T, typename P>
     104           0 : [[nodiscard]] std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const P& params, const std::optional<size_t>& max_length = std::nullopt) noexcept
     105             : {
     106           0 :     const std::vector<uint8_t> buffer{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
     107           0 :     DataStream ds{buffer};
     108           0 :     T obj;
     109             :     try {
     110           0 :         ds >> WithParams(params, obj);
     111           0 :     } catch (const std::ios_base::failure&) {
     112           0 :         return std::nullopt;
     113           0 :     }
     114           0 :     return obj;
     115           0 : }
     116             : 
     117             : template <typename T>
     118       18183 : [[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
     119             : {
     120       18183 :     const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
     121       18183 :     CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
     122       18183 :     T obj;
     123             :     try {
     124       18183 :         ds >> obj;
     125       18183 :     } catch (const std::ios_base::failure&) {
     126        6395 :         return std::nullopt;
     127        6395 :     }
     128       11788 :     return obj;
     129       24578 : }
     130             : 
     131             : template <typename WeakEnumType, size_t size>
     132           0 : [[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
     133             : {
     134           0 :     return fuzzed_data_provider.ConsumeBool() ?
     135           0 :                fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
     136           0 :                WeakEnumType(fuzzed_data_provider.ConsumeIntegral<typename std::underlying_type<WeakEnumType>::type>());
     137             : }
     138             : 
     139           0 : [[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
     140             : {
     141           0 :     return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
     142             : }
     143             : 
     144             : [[nodiscard]] CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max = std::nullopt) noexcept;
     145             : 
     146             : [[nodiscard]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept;
     147             : 
     148             : [[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
     149             : 
     150             : [[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
     151             : 
     152             : [[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const bool maybe_p2wsh = false) noexcept;
     153             : 
     154             : [[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
     155             : 
     156           0 : [[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
     157             : {
     158           0 :     return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
     159             : }
     160             : 
     161           0 : [[nodiscard]] inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
     162             : {
     163           0 :     const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8);
     164           0 :     if (v160.size() != 160 / 8) {
     165           0 :         return {};
     166             :     }
     167           0 :     return uint160{v160};
     168           0 : }
     169             : 
     170         236 : [[nodiscard]] inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
     171             : {
     172         236 :     const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8);
     173         236 :     if (v256.size() != 256 / 8) {
     174          60 :         return {};
     175             :     }
     176         176 :     return uint256{v256};
     177         236 : }
     178             : 
     179           0 : [[nodiscard]] inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
     180             : {
     181           0 :     return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
     182             : }
     183             : 
     184             : [[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept;
     185             : 
     186             : [[nodiscard]] CKey ConsumePrivateKey(FuzzedDataProvider& fuzzed_data_provider, std::optional<bool> compressed = std::nullopt) noexcept;
     187             : 
     188             : template <typename T>
     189           0 : [[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept
     190             : {
     191             :     static_assert(std::is_integral<T>::value, "Integral required.");
     192             :     if (std::numeric_limits<T>::is_signed) {
     193           0 :         if (i > 0) {
     194           0 :             if (j > 0) {
     195           0 :                 return i > (std::numeric_limits<T>::max() / j);
     196             :             } else {
     197           0 :                 return j < (std::numeric_limits<T>::min() / i);
     198             :             }
     199             :         } else {
     200           0 :             if (j > 0) {
     201           0 :                 return i < (std::numeric_limits<T>::min() / j);
     202             :             } else {
     203           0 :                 return i != 0 && (j < (std::numeric_limits<T>::max() / i));
     204             :             }
     205             :         }
     206             :     } else {
     207           0 :         return j != 0 && i > std::numeric_limits<T>::max() / j;
     208             :     }
     209           0 : }
     210             : 
     211             : [[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept;
     212             : 
     213             : /**
     214             :  * Sets errno to a value selected from the given std::array `errnos`.
     215             :  */
     216             : template <typename T, size_t size>
     217           0 : void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T, size>& errnos)
     218             : {
     219           0 :     errno = fuzzed_data_provider.PickValueInArray(errnos);
     220           0 : }
     221             : 
     222             : /*
     223             :  * Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
     224             :  * standard library functions that set errno, or in other contexts where the value of errno
     225             :  * might be relevant for the execution path that will be taken.
     226             :  */
     227           0 : inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
     228             : {
     229           0 :     errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
     230           0 : }
     231             : 
     232             : /**
     233             :  * Returns a byte vector of specified size regardless of the number of remaining bytes available
     234             :  * from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
     235             :  */
     236             : template<typename B = uint8_t>
     237           0 : [[nodiscard]] inline std::vector<B> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept
     238             : {
     239             :     static_assert(sizeof(B) == 1);
     240           0 :     auto random_bytes = fuzzed_data_provider.ConsumeBytes<B>(length);
     241           0 :     random_bytes.resize(length);
     242           0 :     return random_bytes;
     243           0 : }
     244             : 
     245             : class FuzzedFileProvider
     246             : {
     247             :     FuzzedDataProvider& m_fuzzed_data_provider;
     248           0 :     int64_t m_offset = 0;
     249             : 
     250             : public:
     251           0 :     FuzzedFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
     252             :     {
     253           0 :     }
     254             : 
     255             :     FILE* open();
     256             : 
     257             :     static ssize_t read(void* cookie, char* buf, size_t size);
     258             : 
     259             :     static ssize_t write(void* cookie, const char* buf, size_t size);
     260             : 
     261             :     static int seek(void* cookie, int64_t* offset, int whence);
     262             : 
     263             :     static int close(void* cookie);
     264             : };
     265             : 
     266           0 : [[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
     267             : {
     268           0 :     return {fuzzed_data_provider};
     269             : }
     270             : 
     271             : class FuzzedAutoFileProvider
     272             : {
     273             :     FuzzedFileProvider m_fuzzed_file_provider;
     274             : 
     275             : public:
     276           0 :     FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_file_provider{fuzzed_data_provider}
     277             :     {
     278           0 :     }
     279             : 
     280           0 :     AutoFile open()
     281             :     {
     282           0 :         return AutoFile{m_fuzzed_file_provider.open()};
     283           0 :     }
     284             : };
     285             : 
     286           0 : [[nodiscard]] inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
     287             : {
     288           0 :     return {fuzzed_data_provider};
     289             : }
     290             : 
     291             : #define WRITE_TO_STREAM_CASE(type, consume) \
     292             :     [&] {                                   \
     293             :         type o = consume;                   \
     294             :         stream << o;                        \
     295             :     }
     296             : template <typename Stream>
     297           0 : void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
     298             : {
     299           0 :     while (fuzzed_data_provider.ConsumeBool()) {
     300             :         try {
     301           0 :             CallOneOf(
     302           0 :                 fuzzed_data_provider,
     303           0 :                 WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()),
     304           0 :                 WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()),
     305           0 :                 WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()),
     306           0 :                 WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()),
     307           0 :                 WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()),
     308           0 :                 WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()),
     309           0 :                 WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()),
     310           0 :                 WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()),
     311           0 :                 WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
     312           0 :                 WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)),
     313           0 :                 WRITE_TO_STREAM_CASE(std::vector<uint8_t>, ConsumeRandomLengthIntegralVector<uint8_t>(fuzzed_data_provider)));
     314           0 :         } catch (const std::ios_base::failure&) {
     315             :             break;
     316           0 :         }
     317             :     }
     318           0 : }
     319             : 
     320             : #define READ_FROM_STREAM_CASE(type) \
     321             :     [&] {                           \
     322             :         type o;                     \
     323             :         stream >> o;                \
     324             :     }
     325             : template <typename Stream>
     326           0 : void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
     327             : {
     328           0 :     while (fuzzed_data_provider.ConsumeBool()) {
     329             :         try {
     330           0 :             CallOneOf(
     331           0 :                 fuzzed_data_provider,
     332           0 :                 READ_FROM_STREAM_CASE(bool),
     333           0 :                 READ_FROM_STREAM_CASE(int8_t),
     334           0 :                 READ_FROM_STREAM_CASE(uint8_t),
     335           0 :                 READ_FROM_STREAM_CASE(int16_t),
     336           0 :                 READ_FROM_STREAM_CASE(uint16_t),
     337           0 :                 READ_FROM_STREAM_CASE(int32_t),
     338           0 :                 READ_FROM_STREAM_CASE(uint32_t),
     339           0 :                 READ_FROM_STREAM_CASE(int64_t),
     340           0 :                 READ_FROM_STREAM_CASE(uint64_t),
     341           0 :                 READ_FROM_STREAM_CASE(std::string),
     342           0 :                 READ_FROM_STREAM_CASE(std::vector<uint8_t>));
     343           0 :         } catch (const std::ios_base::failure&) {
     344             :             break;
     345           0 :         }
     346             :     }
     347           0 : }
     348             : 
     349             : #endif // BITCOIN_TEST_FUZZ_UTIL_H

Generated by: LCOV version 1.14