From 1db8abb7fc62cd9e2ab417d167fbfebf5b5bc56c Mon Sep 17 00:00:00 2001 From: Adrien Beraud Date: Mon, 26 Oct 2026 15:24:19 -0400 Subject: [PATCH] c: align hash structs with native types --- BUILD.md | 4 ++++ c/opendht.cpp | 5 +++++ c/opendht_c.h | 13 +++++++++++-- rust/src/ffi.rs | 4 ++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/BUILD.md b/BUILD.md index da33f292..e207b8ce 100644 --- a/BUILD.md +++ b/BUILD.md @@ -122,6 +122,10 @@ Enable `OPENDHT_C=ON` to build the C ABI. With `BUILD_TESTING=ON`, CTest runs enabled. Rust regression and callback-lifetime tests run with Cargo; see [the Rust binding guide](rust/README.md) for build and library-path settings. +`dht_infohash` and `dht_pkid` have `uint32_t` alignment, matching the native hash +types, while retaining their 20-byte and 32-byte sizes. Rebuild consumers against +the updated header; foreign-language declarations must match this alignment. + C handles returned by constructors, imports, and reference functions are owned and require their matching delete/unref function. Data views, string getters, query fields, and callback arguments are borrowed: copy them or take a reference diff --git a/c/opendht.cpp b/c/opendht.cpp index e1c49e4b..390091a3 100644 --- a/c/opendht.cpp +++ b/c/opendht.cpp @@ -12,6 +12,11 @@ using PrivkeySp = std::shared_ptr; using PubkeySp = std::shared_ptr; using CertSp = std::shared_ptr; +static_assert(sizeof(dht_infohash) == sizeof(dht::InfoHash)); +static_assert(alignof(dht_infohash) == alignof(dht::InfoHash)); +static_assert(sizeof(dht_pkid) == sizeof(dht::PkId)); +static_assert(alignof(dht_pkid) == alignof(dht::PkId)); + struct CompletionGuard { CompletionGuard(dht_done_cb callback, void* data) diff --git a/c/opendht_c.h b/c/opendht_c.h index dcdc00ef..68ab868c 100644 --- a/c/opendht_c.h +++ b/c/opendht_c.h @@ -39,9 +39,17 @@ OPENDHT_C_PUBLIC dht_data_view dht_blob_get_data(const dht_blob* data); OPENDHT_C_PUBLIC void dht_blob_delete(dht_blob* data); // dht::InfoHash +#ifdef __cplusplus +#define OPENDHT_C_ALIGN_UINT32 alignas(uint32_t) +#elif defined(_MSC_VER) +#define OPENDHT_C_ALIGN_UINT32 __declspec(align(4)) +#else +#define OPENDHT_C_ALIGN_UINT32 _Alignas(uint32_t) +#endif + struct OPENDHT_C_PUBLIC dht_infohash { - uint8_t d[HASH_LEN]; + OPENDHT_C_ALIGN_UINT32 uint8_t d[HASH_LEN]; }; typedef struct dht_infohash dht_infohash; OPENDHT_C_PUBLIC void dht_infohash_zero(dht_infohash* h); @@ -56,9 +64,10 @@ OPENDHT_C_PUBLIC bool dht_infohash_is_zero(const dht_infohash* h); // dht::PkId struct OPENDHT_C_PUBLIC dht_pkid { - uint8_t d[32]; + OPENDHT_C_ALIGN_UINT32 uint8_t d[32]; }; typedef struct dht_pkid dht_pkid; +#undef OPENDHT_C_ALIGN_UINT32 OPENDHT_C_PUBLIC const char* dht_pkid_print(const dht_pkid* h); // dht::crypto::PublicKey diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index 2630b021..edd53838 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -26,13 +26,13 @@ pub struct Blob { _thread_bound: std::marker::PhantomData<*mut ()>, } -#[repr(C)] +#[repr(C, align(4))] #[derive(PartialEq)] pub struct InfoHash { pub d: [u8; HASH_LEN], } -#[repr(C)] +#[repr(C, align(4))] pub struct PkId { pub d: [u8; PKID_LEN], }