Skip to content

Commit 6657bcb

Browse files
committed
kernel: allow null data_directory
An empty path may be represented with a nullptr. For example, std::string_view::data() may return nullptr. Removes the BITCOINKERNEL_ARG_NONNULL attribute for data_directory, and instead handles such null arguments in the implementation. Also documents how BITCOINKERNEL_ARG_NONNULL should be used.
1 parent a3ac59a commit 6657bcb

File tree

4 files changed

+39
-8
lines changed

4 files changed

+39
-8
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,10 @@ btck_BlockValidationResult btck_block_validation_state_get_block_validation_resu
896896

897897
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)
898898
{
899+
if (data_dir == nullptr || data_dir_len == 0 || blocks_dir == nullptr || blocks_dir_len == 0) {
900+
LogError("Failed to create chainstate manager options: dir must be non-null and non-empty");
901+
return nullptr;
902+
}
899903
try {
900904
fs::path abs_data_dir{fs::absolute(fs::PathFromString({data_dir, data_dir_len}))};
901905
fs::create_directories(abs_data_dir);

src/kernel/bitcoinkernel.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535
#else
3636
#define BITCOINKERNEL_WARN_UNUSED_RESULT
3737
#endif
38+
39+
/**
40+
* BITCOINKERNEL_ARG_NONNULL is a compiler attribute used to indicate that
41+
* certain pointer arguments to a function are not expected to be null.
42+
*
43+
* Callers must not pass a null pointer for arguments marked with this attribute,
44+
* as doing so may result in undefined behavior. This attribute should only be
45+
* used for arguments where a null pointer is unambiguously a programmer error,
46+
* such as for opaque handles, and not for pointers to raw input data that might
47+
* validly be null (e.g., from an empty std::span or std::string).
48+
*/
3849
#if !defined(BITCOINKERNEL_BUILD) && defined(__GNUC__)
3950
#define BITCOINKERNEL_ARG_NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
4051
#else
@@ -933,19 +944,20 @@ BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_bl
933944
* @brief Create options for the chainstate manager.
934945
*
935946
* @param[in] context Non-null, the created options and through it the chainstate manager will
936-
associate with this kernel context for the duration of their lifetimes.
937-
* @param[in] data_directory Non-null, path string of the directory containing the chainstate data.
938-
* If the directory does not exist yet, it will be created.
939-
* @param[in] blocks_directory Non-null, path string of the directory containing the block data. If
940-
* the directory does not exist yet, it will be created.
947+
* associate with this kernel context for the duration of their lifetimes.
948+
* @param[in] data_directory Non-null, non-empty path string of the directory containing the
949+
* chainstate data. If the directory does not exist yet, it will be
950+
* created.
951+
* @param[in] blocks_directory Non-null, non-empty path string of the directory containing the block
952+
* data. If the directory does not exist yet, it will be created.
941953
* @return The allocated chainstate manager options, or null on error.
942954
*/
943955
BITCOINKERNEL_API btck_ChainstateManagerOptions* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_options_create(
944956
const btck_Context* context,
945957
const char* data_directory,
946958
size_t data_directory_len,
947959
const char* blocks_directory,
948-
size_t blocks_directory_len) BITCOINKERNEL_ARG_NONNULL(1, 2);
960+
size_t blocks_directory_len) BITCOINKERNEL_ARG_NONNULL(1);
949961

950962
/**
951963
* @brief Set the number of available worker threads used during validation.

src/kernel/bitcoinkernel_wrapper.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,9 @@ class Context : public Handle<btck_Context, btck_context_copy, btck_context_dest
937937
class ChainstateManagerOptions : public UniqueHandle<btck_ChainstateManagerOptions, btck_chainstate_manager_options_destroy>
938938
{
939939
public:
940-
ChainstateManagerOptions(const Context& context, const std::string& data_dir, const std::string& blocks_dir)
941-
: UniqueHandle{btck_chainstate_manager_options_create(context.get(), data_dir.c_str(), data_dir.length(), blocks_dir.c_str(), blocks_dir.length())}
940+
ChainstateManagerOptions(const Context& context, std::string_view data_dir, std::string_view blocks_dir)
941+
: UniqueHandle{btck_chainstate_manager_options_create(
942+
context.get(), data_dir.data(), data_dir.length(), blocks_dir.data(), blocks_dir.length())}
942943
{
943944
}
944945

src/test/kernel/test_kernel.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,20 @@ BOOST_AUTO_TEST_CASE(btck_chainman_tests)
625625
ChainstateManagerOptions chainman_opts{context, test_directory.m_directory.string(), (test_directory.m_directory / "blocks").string()};
626626
ChainMan chainman{context, chainman_opts};
627627
}
628+
{ // null or empty data_directory or blocks_directory are not allowed
629+
Context context{};
630+
auto valid_dir{test_directory.m_directory.string()};
631+
std::vector<std::pair<std::string_view, std::string_view>> illegal_cases{
632+
{"", valid_dir},
633+
{valid_dir, {nullptr, 0}},
634+
{"", ""},
635+
{{nullptr, 0}, {nullptr, 0}},
636+
};
637+
for (auto& [data_dir, blocks_dir] : illegal_cases) {
638+
BOOST_CHECK_THROW(ChainstateManagerOptions(context, data_dir, blocks_dir),
639+
std::runtime_error);
640+
};
641+
}
628642

629643
auto notifications{std::make_shared<TestKernelNotifications>()};
630644
auto context{create_context(notifications, ChainType::MAINNET)};

0 commit comments

Comments
 (0)