mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
Merge bitcoin/bitcoin#36111: rpc: bound memory for overlong Bech32 errors
7fcaccd9d0bech32: bound overlength error locations (Lőrinc) Pull request description: **Problem:** `validateaddress` reports likely error positions for invalid Bech32 inputs, including multiple useful positions for character and checksum errors. For an overlength input, `LocateErrors()` returns every position after the 90-character limit, which the RPC converts to a `UniValue` number before serializing the response. A near-limit authenticated request therefore creates about 33 million `int` values and 33 million `UniValue` objects. **Fix:** Return position 90 for an overlength input, which identifies where the single length violation begins. Character and checksum errors continue to return multiple useful positions when they can be determined. The tests now include an oversized example and pin the bounded result. **Reproducer:** Peak memory usage for a near-limit authenticated request: <details> <summary>Linux reproducer</summary> ```bash sed -i "/def test_validateaddress(self):/a\\ self.nodes[0].validateaddress('bcrt1' + 'q' * (2**25 - 100))\\ __import__('time').sleep(30)" test/functional/rpc_invalid_address_message.py cmake -B build && cmake --build build -j2 build/test/functional/rpc_invalid_address_message.py >/dev/null 2>&1 & sleep 20 && awk '/VmHWM/' /proc/$(pgrep bitcoind)/status ``` </details> ```text Before ████████████████████████ 5.69 GiB After █░░░░░░░░░░░░░░░░░░░░░░░ 240 MiB ``` ACKs for top commit: maflcko: lgtm ACK7fcaccd9d0sedited: ACK7fcaccd9d0janb84: ACK7fcaccd9d0Tree-SHA512: 3d439774d394f081b8107f8131963f7aa23ed048b0d6d349a80f9b3481fefeef7b5ce239fbd33606ad1f4960e6bfd899f968c50febc70d38b2fe731c6049583f
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
||||
namespace bech32
|
||||
@@ -404,8 +403,7 @@ std::pair<std::string, std::vector<int>> LocateErrors(const std::string& str, Ch
|
||||
std::vector<int> error_locations{};
|
||||
|
||||
if (str.size() > limit) {
|
||||
error_locations.resize(str.size() - limit);
|
||||
std::iota(error_locations.begin(), error_locations.end(), static_cast<int>(limit));
|
||||
error_locations.push_back(static_cast<int>(limit));
|
||||
return std::make_pair("Bech32 string too long", std::move(error_locations));
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
|
||||
"A12uEL5L",
|
||||
"abcdef1qpzrz9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
|
||||
"test1zg69w7y6hn0aqy352euf40x77qddq3dc",
|
||||
std::string(100, 'q'),
|
||||
};
|
||||
static const std::pair<std::string, std::vector<int>> ERRORS[] = {
|
||||
{"Invalid character or mixed case", {0}},
|
||||
@@ -89,6 +90,7 @@ BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
|
||||
{"Invalid character or mixed case", {3}},
|
||||
{"Invalid Bech32 checksum", {11}},
|
||||
{"Invalid Bech32 checksum", {9, 16}},
|
||||
{"Bech32 string too long", {90}},
|
||||
};
|
||||
static_assert(std::size(CASES) == std::size(ERRORS), "Bech32 CASES and ERRORS should have the same length");
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
|
||||
self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
|
||||
self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
|
||||
self.check_invalid(BECH32_INVALID_V0_SIZE, "Invalid Bech32 v0 address program size (21 bytes), per BIP141")
|
||||
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108)))
|
||||
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', [90])
|
||||
self.check_invalid(BECH32_ONE_ERROR, 'Invalid Bech32 checksum', [9])
|
||||
self.check_invalid(BECH32_TWO_ERRORS, 'Invalid Bech32 checksum', [22, 43])
|
||||
self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid Bech32 checksum', [38])
|
||||
|
||||
Reference in New Issue
Block a user