From 570a6276400401f56ac5bb3a81c43e9553a3ee8a Mon Sep 17 00:00:00 2001 From: stringintech Date: Mon, 18 May 2026 09:34:39 +0330 Subject: [PATCH] kernel: assert invalid buffer preconditions in `btck_*_create` functions Switch buffer `ptr == nullptr && len > 0` checks from `nullptr` returns to assertions. These checks represent invalid caller preconditions, not failures encountered while deserializing or constructing the requested object. `btck_block_header_create` additionally asserts the pre-existing documented length contract (must be 80 bytes). --- src/kernel/bitcoinkernel.cpp | 20 +++++++------------- src/kernel/bitcoinkernel.h | 13 ++++++------- src/test/kernel/test_kernel.cpp | 4 ---- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index aa095cab74f..3d0eef77ffb 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -506,9 +506,7 @@ struct btck_ConsensusParams: Handle {}; btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len) { - if (raw_transaction == nullptr && raw_transaction_len != 0) { - return nullptr; - } + assert(raw_transaction != nullptr || raw_transaction_len == 0); try { SpanReader stream{std::span{reinterpret_cast(raw_transaction), raw_transaction_len}}; return btck_Transaction::create(std::make_shared(deserialize, TX_WITH_WITNESS, stream)); @@ -573,9 +571,7 @@ void btck_transaction_destroy(btck_Transaction* transaction) btck_ScriptPubkey* btck_script_pubkey_create(const void* script_pubkey, size_t script_pubkey_len) { - if (script_pubkey == nullptr && script_pubkey_len != 0) { - return nullptr; - } + assert(script_pubkey != nullptr || script_pubkey_len == 0); auto data = std::span{reinterpret_cast(script_pubkey), script_pubkey_len}; return btck_ScriptPubkey::create(data.begin(), data.end()); } @@ -965,7 +961,9 @@ btck_BlockValidationResult btck_block_validation_state_get_block_validation_resu btck_ChainstateManagerOptions* btck_chainstate_manager_options_create(const btck_Context* context, const char* data_dir, size_t data_dir_len, const char* blocks_dir, size_t blocks_dir_len) { - if (data_dir == nullptr || data_dir_len == 0 || blocks_dir == nullptr || blocks_dir_len == 0) { + assert(data_dir != nullptr || data_dir_len == 0); + assert(blocks_dir != nullptr || blocks_dir_len == 0); + if (data_dir_len == 0 || blocks_dir_len == 0) { LogError("Failed to create chainstate manager options: dir must be non-null and non-empty"); return nullptr; } @@ -1116,9 +1114,7 @@ int btck_chainstate_manager_import_blocks(btck_ChainstateManager* chainman, cons btck_Block* btck_block_create(const void* raw_block, size_t raw_block_length) { - if (raw_block == nullptr && raw_block_length != 0) { - return nullptr; - } + assert(raw_block != nullptr || raw_block_length == 0); auto block{std::make_shared()}; SpanReader stream{std::span{reinterpret_cast(raw_block), raw_block_length}}; @@ -1381,9 +1377,7 @@ int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entr btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len) { - if (raw_block_header == nullptr && raw_block_header_len != 0) { - return nullptr; - } + assert(raw_block_header != nullptr && raw_block_header_len == 80); auto header{std::make_unique()}; SpanReader stream{std::span{reinterpret_cast(raw_block_header), raw_block_header_len}}; diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h index 577c4c0a329..8afef786262 100644 --- a/src/kernel/bitcoinkernel.h +++ b/src/kernel/bitcoinkernel.h @@ -1144,12 +1144,11 @@ BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT bt * * @param[in] context Non-null, the created options and through it the chainstate manager will * associate with this kernel context for the duration of their lifetimes. - * @param[in] data_directory Non-null, non-empty path string of the directory containing the - * chainstate data. If the directory does not exist yet, it will be - * created. - * @param[in] blocks_directory Non-null, non-empty path string of the directory containing the block - * data. If the directory does not exist yet, it will be created. - * @return The allocated chainstate manager options, or null on error. + * @param[in] data_directory Path string of the directory containing the chainstate data. If the directory + * does not exist yet, it will be created. + * @param[in] blocks_directory Path string of the directory containing the block data. If the directory + * does not exist yet, it will be created. + * @return The allocated chainstate manager options, or null on error (e.g. if a path is invalid). */ BITCOINKERNEL_API btck_ChainstateManagerOptions* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_options_create( const btck_Context* context, @@ -1869,7 +1868,7 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash); * @return btck_BlockHeader, or null on error. */ BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create( - const void* raw_block_header, size_t raw_block_header_len); + const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1); /** * @brief Copy a btck_BlockHeader. diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp index 0489839daca..ca0e7cd662b 100644 --- a/src/test/kernel/test_kernel.cpp +++ b/src/test/kernel/test_kernel.cpp @@ -683,10 +683,6 @@ BOOST_AUTO_TEST_CASE(btck_block_header_tests) BlockHeader header_1{hex_string_to_byte_vec("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")}; CheckHandle(header_0, header_1); - // Test error handling for invalid data - BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("00")}, std::runtime_error); - BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("")}, std::runtime_error); - // Test all header field accessors using mainnet block 1 auto mainnet_block_1_header = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299"); BlockHeader header{mainnet_block_1_header};