Repository: bitcoin/bitcoin (language: cpp)

Issue:
fuzz: connman target: terminate called after throwing an instance of 'std::bad_alloc'
Base64 reproducer:

```
XP//////////BiAgICBbICAHAADg/4Hf394gICAgICAgIAAgICAgIHb/FiAgICAgdGggtyAgICCB
CAQAIDAXIAEAAAAAAAAAAQAAAAAAAAABAAAAAAAAgYGBgYGB7QH//2ZoZWNrcHRhYWFhYWFhl2Fh
YWFhYWFhYWFhYWFhYWFhYWFhYWFhYQAAAAAAAFxjYWFhYWFhYWFcdIFhYWFhZHJh9xP3ExPAE8BA
7/cTwBP3ExP398D3AQAAAAAAAASBgYGBgYHtAf///WdldGNmaGVja3B0YWFhYWFhYWFhl2FhYWFh
YWFhYWFhYWFhYWFhYWFhYWFhYQ==
```

```
$ sha1sum ./crash && FUZZ=connman ./bld/src/test/fuzz/fuzz ./crash
c0f5ddd240439f74d6eac83bbb67115b1ad1d209  ./crash
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4221650549
INFO: Loaded 1 modules   (379889 inline 8-bit counters): 379889 [0x5ebd0d22d8e0, 0x5ebd0d28a4d1),
INFO: Loaded 1 PC tables (379889 PCs): 379889 [0x5ebd0d28a4d8,0x5ebd0d8563e8),
./bld/src/test/fuzz/fuzz: Running 1 inputs 1 time(s) each.
Running: ./crash
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
==3597798== ERROR: libFuzzer: deadly signal
    #0 0x5ebd0be47f08 in __sanitizer_print_stack_trace (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x9bdf08) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #1 0x5ebd0be1a1bc in fuzzer::PrintStackTrace() (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x9901bc) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #2 0x5ebd0bdff267 in fuzzer::Fuzzer::CrashCallback() (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x975267) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #3 0x75d5b704531f  (/lib/x86_64-linux-gnu/libc.so.6+0x4531f) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #4 0x75d5b709eb1b in pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x9eb1b) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #5 0x75d5b704526d in raise (/lib/x86_64-linux-gnu/libc.so.6+0x4526d) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #6 0x75d5b70288fe in abort (/lib/x86_64-linux-gnu/libc.so.6+0x288fe) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #7 0x75d5b76a5ff4  (/lib/x86_64-linux-gnu/libstdc++.so.6+0xa5ff4) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #8 0x75d5b76bb0d9  (/lib/x86_64-linux-gnu/libstdc++.so.6+0xbb0d9) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #9 0x75d5b76a5a54 in std::terminate() (/lib/x86_64-linux-gnu/libstdc++.so.6+0xa5a54) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #10 0x75d5b76bb390 in __cxa_throw (/lib/x86_64-linux-gnu/libstdc++.so.6+0xbb390) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #11 0x75d5b76a5ac7  (/lib/x86_64-linux-gnu/libstdc++.so.6+0xa5ac7) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #12 0x5ebd0c7d8d8e in std::__new_allocator<CAddress>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27
    #13 0x5ebd0c7d8d8e in std::allocator<CAddress>::allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/allocator.h:198:32
    #14 0x5ebd0c7d8d8e in std::allocator_traits<std::allocator<CAddress>>::allocate(std::allocator<CAddress>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20
    #15 0x5ebd0c7d8d8e in std::_Vector_base<CAddress, std::allocator<CAddress>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20
    #16 0x5ebd0c7d8d8e in std::vector<CAddress, std::allocator<CAddress>>::reserve(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:79:22
    #17 0x5ebd0c7d8d8e in AddrManImpl::GetAddr_(unsigned long, unsigned long, std::optional<Network>, bool) const bld/src/./src/addrman.cpp:827:15
    #18 0x5ebd0c7df451 in AddrManImpl::GetAddr(unsigned long, unsigned long, std::optional<Network>, bool) const bld/src/./src/addrman.cpp:1231:22
    #19 0x5ebd0c7e8a7a in AddrMan::GetAddr(unsigned long, unsigned long, std::optional<Network>, bool) const bld/src/./src/addrman.cpp:1332:20
    #20 0x5ebd0c8b6311 in CConnman::GetAddresses(unsigned long, unsigned long, std::optional<Network>, bool) const bld/src/./src/net.cpp:3438:47
    #21 0x5ebd0c8b6cb4 in CConnman::GetAddresses(CNode&, unsigned long, unsigned long) bld/src/./src/net.cpp:3461:46
    #22 0x5ebd0bf19d2f in connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_12::operator()() const bld/src/test/fuzz/./src/test/fuzz/connman.cpp:120:31
    #23 0x5ebd0bf19d2f in unsigned long CallOneOf<connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_3, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_4, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_6, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_7, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_8, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_9, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_10, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_11, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_12, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_13, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_14, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_15, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_16, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_17, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_18, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_19>(FuzzedDataProvider&, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_3, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_4, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_6, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_7, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_8, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_9, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_10, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_11, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_12, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_13, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_14, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_15, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_16, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_17, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_18, connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_19) bld/src/test/fuzz/./src/test/fuzz/util.h:42:27
    #24 0x5ebd0bf19d2f in connman_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>) bld/src/test/fuzz/./src/test/fuzz/connman.cpp:76:9
    #25 0x5ebd0c18fe93 in std::function<void (std::span<unsigned char const, 18446744073709551615ul>)>::operator()(std::span<unsigned char const, 18446744073709551615ul>) const /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:591:9
    #26 0x5ebd0c18fe93 in LLVMFuzzerTestOneInput bld/src/test/fuzz/util/./src/test/fuzz/fuzz.cpp:211:5
    #27 0x5ebd0be0083f in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x97683f) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #28 0x5ebd0bde8533 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x95e533) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #29 0x5ebd0bdee6e1 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x9646e1) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #30 0x5ebd0be1ad26 in main (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x990d26) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)
    #31 0x75d5b702a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #32 0x75d5b702a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #33 0x5ebd0bde2c84 in _start (/root/fuzz_dir_nosan/scratch/fuzz_gen/code/bld/src/test/fuzz/fuzz+0x958c84) (BuildId: d2b9dd90cecdb569dc1f9fffe51cb04f92ef4f5b)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal



Discussion / hints:
Working on it. We should limit `max_addresses` and `max_pct`.

Fix patch:
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 43e7b6a32ce64..9c3a24db900f5 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -812,9 +812,11 @@ nid_type AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) c
 std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
 {
     AssertLockHeld(cs);
+    Assume(max_pct <= 100);
 
     size_t nNodes = vRandom.size();
     if (max_pct != 0) {
+        max_pct = std::min(max_pct, size_t{100});
         nNodes = max_pct * nNodes / 100;
     }
     if (max_addresses != 0) {
diff --git a/src/addrman.h b/src/addrman.h
index ba6e13bf97ead..2ddf1468624c4 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -166,7 +166,7 @@ class AddrMan
      * Return all or many randomly selected addresses, optionally by network.
      *
      * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
-     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
+     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all). Value must be from 0 to 100.
      * @param[in] network        Select only addresses of this network (nullopt = all).
      * @param[in] filtered       Select only addresses that are considered good quality (false = all).
      *
diff --git a/src/net.h b/src/net.h
index 6b63e2cc0d11f..6f3e6eda7beda 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1152,7 +1152,7 @@ class CConnman
      * Return all or many randomly selected addresses, optionally by network.
      *
      * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
-     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
+     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all). Value must be from 0 to 100.
      * @param[in] network        Select only addresses of this network (nullopt = all).
      * @param[in] filtered       Select only addresses that are considered high quality (false = all).
      */


Test patch:
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index a7e7f49d9f470..53dd7215d2ea5 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -173,7 +173,7 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
         network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS);
     }
     auto max_addresses = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
-    auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
+    auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);
     auto filtered = fuzzed_data_provider.ConsumeBool();
     (void)const_addr_man.GetAddr(max_addresses, max_pct, network, filtered);
 
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index f2bf44c76139e..6e0c3bc236c35 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -110,13 +110,13 @@ FUZZ_TARGET(connman, .init = initialize_connman)
             },
             [&] {
                 auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
-                auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>();
+                auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);
                 auto filtered = fuzzed_data_provider.ConsumeBool();
                 (void)connman.GetAddresses(max_addresses, max_pct, /*network=*/std::nullopt, filtered);
             },
             [&] {
                 auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
-                auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>();
+                auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);
                 (void)connman.GetAddresses(/*requestor=*/random_node, max_addresses, max_pct);
             },
             [&] {