diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index 57a3ffbd2..00f8fea57 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -1,202 +1,203 @@ # Fuzzer test harness add_custom_target(bitcoin-fuzzers) define_property(GLOBAL PROPERTY FUZZ_TARGETS BRIEF_DOCS "List of fuzz targets" FULL_DOCS "A list of the fuzz targets" ) set_property(GLOBAL APPEND PROPERTY FUZZ_TARGETS bitcoin-fuzzers) include(InstallationHelper) macro(add_fuzz_target TARGET EXE_NAME) add_executable(${TARGET} EXCLUDE_FROM_ALL fuzz.cpp ${ARGN} ) set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${EXE_NAME}) target_link_libraries(${TARGET} server testutil rpcclient) add_dependencies(bitcoin-fuzzers ${TARGET}) set_property(GLOBAL APPEND PROPERTY FUZZ_TARGETS ${TARGET}) install_target(${TARGET} COMPONENT fuzzer EXCLUDE_FROM_ALL ) endmacro() function(add_regular_fuzz_targets) foreach(_fuzz_test_name ${ARGN}) sanitize_target_name("fuzz-" ${_fuzz_test_name} _fuzz_target_name) add_fuzz_target( ${_fuzz_target_name} ${_fuzz_test_name} # Sources "${_fuzz_test_name}.cpp" ) endforeach() endfunction() include(SanitizeHelper) function(add_deserialize_fuzz_targets) foreach(_fuzz_test_name ${ARGN}) sanitize_target_name("fuzz-" ${_fuzz_test_name} _fuzz_target_name) add_fuzz_target( ${_fuzz_target_name} ${_fuzz_test_name} # Sources deserialize.cpp ) sanitize_c_cxx_definition("" ${_fuzz_test_name} _target_definition) string(TOUPPER ${_target_definition} _target_definition) target_compile_definitions(${_fuzz_target_name} PRIVATE ${_target_definition}) endforeach() endfunction() function(add_process_message_fuzz_targets) foreach(_fuzz_test_name ${ARGN}) sanitize_target_name("fuzz-process_message_" ${_fuzz_test_name} _fuzz_target_name) add_fuzz_target( ${_fuzz_target_name} process_message_${_fuzz_test_name} # Sources process_message.cpp ) target_compile_definitions(${_fuzz_target_name} PRIVATE MESSAGE_TYPE=${_fuzz_test_name}) endforeach() endfunction() add_regular_fuzz_targets( addition_overflow addrdb asmap base_encode_decode block block_header blockfilter bloom_filter cashaddr chain checkqueue cuckoocache descriptor_parse eval_script fee_rate fees flatfile float hex http_request integer key key_io locale merkleblock multiplication_overflow net_permissions netaddress p2p_transport_deserializer parse_hd_keypath parse_iso8601 parse_numbers parse_script parse_univalue + prevector pow process_message process_messages protocol psbt random rolling_bloom_filter script script_flags script_ops scriptnum_ops signature_checker span spanparsing string strprintf timedata transaction tx_in tx_out ) add_deserialize_fuzz_targets( addr_info_deserialize address_deserialize addrman_deserialize banentry_deserialize block_deserialize block_file_info_deserialize block_filter_deserialize block_header_and_short_txids_deserialize blockheader_deserialize blocklocator_deserialize blockmerkleroot blocktransactions_deserialize blocktransactionsrequest_deserialize blockundo_deserialize bloomfilter_deserialize coins_deserialize diskblockindex_deserialize fee_rate_deserialize flat_file_pos_deserialize inv_deserialize key_origin_info_deserialize merkle_block_deserialize messageheader_deserialize netaddr_deserialize out_point_deserialize partial_merkle_tree_deserialize partially_signed_transaction_deserialize prefilled_transaction_deserialize psbt_input_deserialize psbt_output_deserialize pub_key_deserialize script_deserialize service_deserialize snapshotmetadata_deserialize sub_net_deserialize tx_in_deserialize txoutcompressor_deserialize txundo_deserialize uint160_deserialize uint256_deserialize ) add_process_message_fuzz_targets( addr block blocktxn cmpctblock feefilter filteradd filterclear filterload getaddr getblocks getblocktxn getdata getheaders headers inv mempool notfound ping pong sendcmpct sendheaders tx verack version ) diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp new file mode 100644 index 000000000..64f8b72ba --- /dev/null +++ b/src/test/fuzz/prevector.cpp @@ -0,0 +1,270 @@ +// Copyright (c) 2015-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 + +namespace { + +template class prevector_tester { + typedef std::vector realtype; + realtype real_vector; + realtype real_vector_alt; + + typedef prevector pretype; + pretype pre_vector; + pretype pre_vector_alt; + + typedef typename pretype::size_type Size; + +public: + void test() const { + const pretype &const_pre_vector = pre_vector; + assert(real_vector.size() == pre_vector.size()); + assert(real_vector.empty() == pre_vector.empty()); + for (Size s = 0; s < real_vector.size(); s++) { + assert(real_vector[s] == pre_vector[s]); + assert(&(pre_vector[s]) == &(pre_vector.begin()[s])); + assert(&(pre_vector[s]) == &*(pre_vector.begin() + s)); + assert(&(pre_vector[s]) == + &*((pre_vector.end() + s) - real_vector.size())); + } + // assert(realtype(pre_vector) == real_vector); + assert(pretype(real_vector.begin(), real_vector.end()) == pre_vector); + assert(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); + size_t pos = 0; + for (const T &v : pre_vector) { + assert(v == real_vector[pos]); + ++pos; + } + for (const T &v : reverse_iterate(pre_vector)) { + --pos; + assert(v == real_vector[pos]); + } + for (const T &v : const_pre_vector) { + assert(v == real_vector[pos]); + ++pos; + } + for (const T &v : reverse_iterate(const_pre_vector)) { + --pos; + assert(v == real_vector[pos]); + } + CDataStream ss1(SER_DISK, 0); + CDataStream ss2(SER_DISK, 0); + ss1 << real_vector; + ss2 << pre_vector; + assert(ss1.size() == ss2.size()); + for (Size s = 0; s < ss1.size(); s++) { + assert(ss1[s] == ss2[s]); + } + } + + void resize(Size s) { + real_vector.resize(s); + assert(real_vector.size() == s); + pre_vector.resize(s); + assert(pre_vector.size() == s); + } + + void reserve(Size s) { + real_vector.reserve(s); + assert(real_vector.capacity() >= s); + pre_vector.reserve(s); + assert(pre_vector.capacity() >= s); + } + + void insert(Size position, const T &value) { + real_vector.insert(real_vector.begin() + position, value); + pre_vector.insert(pre_vector.begin() + position, value); + } + + void insert(Size position, Size count, const T &value) { + real_vector.insert(real_vector.begin() + position, count, value); + pre_vector.insert(pre_vector.begin() + position, count, value); + } + + template void insert_range(Size position, I first, I last) { + real_vector.insert(real_vector.begin() + position, first, last); + pre_vector.insert(pre_vector.begin() + position, first, last); + } + + void erase(Size position) { + real_vector.erase(real_vector.begin() + position); + pre_vector.erase(pre_vector.begin() + position); + } + + void erase(Size first, Size last) { + real_vector.erase(real_vector.begin() + first, + real_vector.begin() + last); + pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last); + } + + void update(Size pos, const T &value) { + real_vector[pos] = value; + pre_vector[pos] = value; + } + + void push_back(const T &value) { + real_vector.push_back(value); + pre_vector.push_back(value); + } + + void pop_back() { + real_vector.pop_back(); + pre_vector.pop_back(); + } + + void clear() { + real_vector.clear(); + pre_vector.clear(); + } + + void assign(Size n, const T &value) { + real_vector.assign(n, value); + pre_vector.assign(n, value); + } + + Size size() const { return real_vector.size(); } + + Size capacity() const { return pre_vector.capacity(); } + + void shrink_to_fit() { pre_vector.shrink_to_fit(); } + + void swap() { + real_vector.swap(real_vector_alt); + pre_vector.swap(pre_vector_alt); + } + + void move() { + real_vector = std::move(real_vector_alt); + real_vector_alt.clear(); + pre_vector = std::move(pre_vector_alt); + pre_vector_alt.clear(); + } + + void copy() { + real_vector = real_vector_alt; + pre_vector = pre_vector_alt; + } + + void resize_uninitialized(realtype values) { + size_t r = values.size(); + size_t s = real_vector.size() / 2; + if (real_vector.capacity() < s + r) { + real_vector.reserve(s + r); + } + real_vector.resize(s); + pre_vector.resize_uninitialized(s); + for (auto v : values) { + real_vector.push_back(v); + } + auto p = pre_vector.size(); + pre_vector.resize_uninitialized(p + r); + for (auto v : values) { + pre_vector[p] = v; + ++p; + } + } +}; + +} // namespace + +void test_one_input(const std::vector &buffer) { + FuzzedDataProvider prov(buffer.data(), buffer.size()); + prevector_tester<8, int> test; + + while (prov.remaining_bytes()) { + switch ( + prov.ConsumeIntegralInRange(0, 13 + 3 * (test.size() > 0))) { + case 0: + test.insert(prov.ConsumeIntegralInRange(0, test.size()), + prov.ConsumeIntegral()); + break; + case 1: + test.resize(std::max( + 0, std::min(30, (int)test.size() + + prov.ConsumeIntegralInRange(0, 4) - + 2))); + break; + case 2: + test.insert(prov.ConsumeIntegralInRange(0, test.size()), + 1 + prov.ConsumeBool(), + prov.ConsumeIntegral()); + break; + case 3: { + int del = prov.ConsumeIntegralInRange(0, test.size()); + int beg = + prov.ConsumeIntegralInRange(0, test.size() - del); + test.erase(beg, beg + del); + break; + } + case 4: + test.push_back(prov.ConsumeIntegral()); + break; + case 5: { + int values[4]; + int num = 1 + prov.ConsumeIntegralInRange(0, 3); + for (int k = 0; k < num; ++k) { + values[k] = prov.ConsumeIntegral(); + } + test.insert_range( + prov.ConsumeIntegralInRange(0, test.size()), values, + values + num); + break; + } + case 6: { + int num = 1 + prov.ConsumeIntegralInRange(0, 15); + std::vector values(num); + for (auto &v : values) { + v = prov.ConsumeIntegral(); + } + test.resize_uninitialized(values); + break; + } + case 7: + test.reserve(prov.ConsumeIntegralInRange(0, 32767)); + break; + case 8: + test.shrink_to_fit(); + break; + case 9: + test.clear(); + break; + case 10: + test.assign(prov.ConsumeIntegralInRange(0, 32767), + prov.ConsumeIntegral()); + break; + case 11: + test.swap(); + break; + case 12: + test.copy(); + break; + case 13: + test.move(); + break; + case 14: + test.update( + prov.ConsumeIntegralInRange(0, test.size() - 1), + prov.ConsumeIntegral()); + break; + case 15: + test.erase( + prov.ConsumeIntegralInRange(0, test.size() - 1)); + break; + case 16: + test.pop_back(); + break; + } + } + + test.test(); +}