util.h raw

   1  // Copyright (c) 2009-present 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 <pow.h>
  17  #include <primitives/transaction.h>
  18  #include <script/script.h>
  19  #include <serialize.h>
  20  #include <streams.h>
  21  #include <test/fuzz/FuzzedDataProvider.h>
  22  #include <test/fuzz/fuzz.h>
  23  #include <uint256.h>
  24  #include <validation.h>
  25  
  26  #include <algorithm>
  27  #include <array>
  28  #include <cstdint>
  29  #include <cstdio>
  30  #include <optional>
  31  #include <string>
  32  #include <vector>
  33  
  34  class PeerManager;
  35  
  36  template <typename... Callables>
  37  size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
  38  {
  39      constexpr size_t call_size{sizeof...(callables)};
  40      static_assert(call_size >= 1);
  41      const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)};
  42  
  43      size_t i{0};
  44      ((i++ == call_index ? callables() : void()), ...);
  45      return call_size;
  46  }
  47  
  48  template <typename Collection>
  49  auto PickIterator(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
  50  {
  51      const auto sz{col.size()};
  52      assert(sz >= 1);
  53      return std::next(col.begin(), fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
  54  }
  55  
  56  template <typename Collection>
  57  auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
  58  {
  59      return *PickIterator(fuzzed_data_provider, col);
  60  }
  61  
  62  template<typename B = uint8_t>
  63  [[nodiscard]] inline std::vector<B> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
  64  {
  65      static_assert(sizeof(B) == 1);
  66      const std::string s = max_length ?
  67                                fuzzed_data_provider.ConsumeRandomLengthString(*max_length) :
  68                                fuzzed_data_provider.ConsumeRandomLengthString();
  69      std::vector<B> ret(s.size());
  70      std::copy(s.begin(), s.end(), reinterpret_cast<char*>(ret.data()));
  71      return ret;
  72  }
  73  
  74  [[nodiscard]] inline DataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
  75  {
  76      return DataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
  77  }
  78  
  79  [[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      const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
  82      std::vector<std::string> r;
  83      r.reserve(n_elements);
  84      for (size_t i = 0; i < n_elements; ++i) {
  85          r.push_back(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
  86      }
  87      return r;
  88  }
  89  
  90  template <typename T>
  91  [[nodiscard]] inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
  92  {
  93      const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
  94      std::vector<T> r;
  95      r.reserve(n_elements);
  96      for (size_t i = 0; i < n_elements; ++i) {
  97          r.push_back(fuzzed_data_provider.ConsumeIntegral<T>());
  98      }
  99      return r;
 100  }
 101  
 102  template <typename P>
 103  [[nodiscard]] P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept;
 104  
 105  template <typename T, typename P>
 106  [[nodiscard]] std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const P& params, const std::optional<size_t>& max_length = std::nullopt) noexcept
 107  {
 108      const std::vector<uint8_t> buffer{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)};
 109      SpanReader ds{buffer};
 110      T obj;
 111      try {
 112          ds >> params(obj);
 113      } catch (const std::ios_base::failure&) {
 114          return std::nullopt;
 115      }
 116      return obj;
 117  }
 118  
 119  template <typename T>
 120  [[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
 121  {
 122      const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
 123      SpanReader ds{buffer};
 124      T obj;
 125      try {
 126          ds >> obj;
 127      } catch (const std::ios_base::failure&) {
 128          return std::nullopt;
 129      }
 130      return obj;
 131  }
 132  
 133  template <typename T>
 134  [[nodiscard]] inline std::optional<T> ConsumeDeserializableConstructor(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
 135  {
 136      const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
 137      SpanReader ds{buffer};
 138      try {
 139          T obj(deserialize, ds);
 140          return obj;
 141      } catch (const std::ios_base::failure&) {
 142          return std::nullopt;
 143      }
 144  }
 145  
 146  template <typename WeakEnumType, size_t size>
 147  [[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
 148  {
 149      return fuzzed_data_provider.ConsumeBool() ?
 150                 fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
 151                 WeakEnumType(fuzzed_data_provider.ConsumeIntegral<std::underlying_type_t<WeakEnumType>>());
 152  }
 153  
 154  [[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
 155  {
 156      return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
 157  }
 158  
 159  [[nodiscard]] CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max = std::nullopt) noexcept;
 160  
 161  [[nodiscard]] NodeSeconds ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept;
 162  
 163  template <class Dur>
 164  // Having the compiler infer the template argument from the function argument
 165  // is dangerous, because the desired return value generally has a different
 166  // type than the function argument. So std::common_type is used to force the
 167  // call site to specify the type of the return value.
 168  [[nodiscard]] Dur ConsumeDuration(FuzzedDataProvider& fuzzed_data_provider, std::common_type_t<Dur> min, std::common_type_t<Dur> max) noexcept
 169  {
 170      return Dur{fuzzed_data_provider.ConsumeIntegralInRange(min.count(), max.count())};
 171  }
 172  
 173  [[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<Txid>>& prevout_txids, int max_num_in = 10, int max_num_out = 10) noexcept;
 174  
 175  [[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, size_t max_stack_elem_size = 32) noexcept;
 176  
 177  [[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, bool maybe_p2wsh = false) noexcept;
 178  
 179  [[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
 180  
 181  [[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
 182  {
 183      return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
 184  }
 185  
 186  [[nodiscard]] inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
 187  {
 188      const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8);
 189      if (v160.size() != 160 / 8) {
 190          return {};
 191      }
 192      return uint160{v160};
 193  }
 194  
 195  [[nodiscard]] inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
 196  {
 197      const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8);
 198      if (v256.size() != 256 / 8) {
 199          return {};
 200      }
 201      return uint256{v256};
 202  }
 203  
 204  [[nodiscard]] inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
 205  {
 206      return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
 207  }
 208  
 209  [[nodiscard]] inline arith_uint256 ConsumeArithUInt256InRange(FuzzedDataProvider& fuzzed_data_provider, const arith_uint256& min, const arith_uint256& max) noexcept
 210  {
 211      assert(min <= max);
 212      const arith_uint256 range = max - min;
 213      const arith_uint256 value = ConsumeArithUInt256(fuzzed_data_provider);
 214      arith_uint256 result = value;
 215      // Avoid division by 0, in case range + 1 results in overflow.
 216      if (range != ~arith_uint256(0)) {
 217          const arith_uint256 quotient = value / (range + 1);
 218          result = value - (quotient * (range + 1));
 219      }
 220      result += min;
 221      assert(result >= min && result <= max);
 222      return result;
 223  }
 224  
 225  [[nodiscard]] std::map<COutPoint, Coin> ConsumeCoins(FuzzedDataProvider& fuzzed_data_provider) noexcept;
 226  
 227  [[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept;
 228  
 229  [[nodiscard]] CKey ConsumePrivateKey(FuzzedDataProvider& fuzzed_data_provider, std::optional<bool> compressed = std::nullopt) noexcept;
 230  
 231  template <typename T>
 232  [[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept
 233  {
 234      static_assert(std::is_integral_v<T>, "Integral required.");
 235      if (std::numeric_limits<T>::is_signed) {
 236          if (i > 0) {
 237              if (j > 0) {
 238                  return i > (std::numeric_limits<T>::max() / j);
 239              } else {
 240                  return j < (std::numeric_limits<T>::min() / i);
 241              }
 242          } else {
 243              if (j > 0) {
 244                  return i < (std::numeric_limits<T>::min() / j);
 245              } else {
 246                  return i != 0 && (j < (std::numeric_limits<T>::max() / i));
 247              }
 248          }
 249      } else {
 250          return j != 0 && i > std::numeric_limits<T>::max() / j;
 251      }
 252  }
 253  
 254  [[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept;
 255  
 256  /**
 257   * Sets errno to a value selected from the given std::array `errnos`.
 258   */
 259  template <typename T, size_t size>
 260  void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T, size>& errnos)
 261  {
 262      errno = fuzzed_data_provider.PickValueInArray(errnos);
 263  }
 264  
 265  /*
 266   * Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
 267   * standard library functions that set errno, or in other contexts where the value of errno
 268   * might be relevant for the execution path that will be taken.
 269   */
 270  inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
 271  {
 272      errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
 273  }
 274  
 275  /**
 276   * Returns a byte vector of specified size regardless of the number of remaining bytes available
 277   * from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
 278   */
 279  template<typename B = uint8_t>
 280  [[nodiscard]] inline std::vector<B> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept
 281  {
 282      static_assert(sizeof(B) == 1);
 283      auto random_bytes = fuzzed_data_provider.ConsumeBytes<B>(length);
 284      random_bytes.resize(length);
 285      return random_bytes;
 286  }
 287  
 288  class FuzzedFileProvider
 289  {
 290      FuzzedDataProvider& m_fuzzed_data_provider;
 291      int64_t m_offset = 0;
 292  
 293  public:
 294      FuzzedFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
 295      {
 296      }
 297  
 298      FILE* open();
 299  
 300      static ssize_t read(void* cookie, char* buf, size_t size);
 301  
 302      static ssize_t write(void* cookie, const char* buf, size_t size);
 303  
 304      static int seek(void* cookie, int64_t* offset, int whence);
 305  
 306      static int close(void* cookie);
 307  };
 308  
 309  #define WRITE_TO_STREAM_CASE(type, consume) \
 310      [&] {                                   \
 311          type o = consume;                   \
 312          stream << o;                        \
 313      }
 314  template <typename Stream>
 315  void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
 316  {
 317      while (fuzzed_data_provider.ConsumeBool()) {
 318          try {
 319              CallOneOf(
 320                  fuzzed_data_provider,
 321                  WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()),
 322                  WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()),
 323                  WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()),
 324                  WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()),
 325                  WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()),
 326                  WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()),
 327                  WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()),
 328                  WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()),
 329                  WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
 330                  WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)),
 331                  WRITE_TO_STREAM_CASE(std::vector<uint8_t>, ConsumeRandomLengthIntegralVector<uint8_t>(fuzzed_data_provider)));
 332          } catch (const std::ios_base::failure&) {
 333              break;
 334          }
 335      }
 336  }
 337  
 338  #define READ_FROM_STREAM_CASE(type) \
 339      [&] {                           \
 340          type o;                     \
 341          stream >> o;                \
 342      }
 343  template <typename Stream>
 344  void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
 345  {
 346      while (fuzzed_data_provider.ConsumeBool()) {
 347          try {
 348              CallOneOf(
 349                  fuzzed_data_provider,
 350                  READ_FROM_STREAM_CASE(bool),
 351                  READ_FROM_STREAM_CASE(int8_t),
 352                  READ_FROM_STREAM_CASE(uint8_t),
 353                  READ_FROM_STREAM_CASE(int16_t),
 354                  READ_FROM_STREAM_CASE(uint16_t),
 355                  READ_FROM_STREAM_CASE(int32_t),
 356                  READ_FROM_STREAM_CASE(uint32_t),
 357                  READ_FROM_STREAM_CASE(int64_t),
 358                  READ_FROM_STREAM_CASE(uint64_t),
 359                  READ_FROM_STREAM_CASE(std::string),
 360                  READ_FROM_STREAM_CASE(std::vector<uint8_t>));
 361          } catch (const std::ios_base::failure&) {
 362              break;
 363          }
 364      }
 365  }
 366  
 367  inline void FinalizeHeader(CBlockHeader& header, const ChainstateManager& chainman)
 368  {
 369      while (!CheckProofOfWork(header.GetHash(), header.nBits, chainman.GetParams().GetConsensus())) {
 370          ++(header.nNonce);
 371      }
 372  }
 373  
 374  #endif // BITCOIN_TEST_FUZZ_UTIL_H
 375