refactor(compress): move heap CCtx initialization to Rust

Move the ordering-sensitive setup of a privately allocated compression
context behind a Rust callback coordinator while keeping allocation and
context storage in C.  The explicit callback ABI preserves zeroing, custom
allocator publication, BMI2 setup, and parameter-reset order, including
reset-error propagation.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml --all-targets (775 passed)
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets (179 passed)
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; make -j1 -C tests test (all tests completed successfully)
This commit is contained in:
2026-07-20 06:21:05 +02:00
parent a67e6a59df
commit 0b56f667db
2 changed files with 186 additions and 7 deletions
+52 -7
View File
@@ -340,6 +340,29 @@ typedef char ZSTD_rust_create_cctx_state_layout[
== 4 * sizeof(void*)
&& sizeof(ZSTD_rust_createCCtxState) == 5 * sizeof(void*))
? 1 : -1];
typedef void (*ZSTD_rust_initCCtxCallback_f)(void* context);
typedef void (*ZSTD_rust_initCCtxSetCustomMem_f)(
void* context, const void* customMem);
typedef size_t (*ZSTD_rust_initCCtxReset_f)(void* context);
typedef struct {
void* callbackContext;
const void* customMem;
ZSTD_rust_initCCtxCallback_f zero;
ZSTD_rust_initCCtxSetCustomMem_f setCustomMem;
ZSTD_rust_initCCtxCallback_f setBmi2;
ZSTD_rust_initCCtxReset_f reset;
} ZSTD_rust_initCCtxState;
size_t ZSTD_rust_initCCtx(const ZSTD_rust_initCCtxState* state);
typedef char ZSTD_rust_init_cctx_state_layout[
(offsetof(ZSTD_rust_initCCtxState, callbackContext) == 0
&& offsetof(ZSTD_rust_initCCtxState, customMem) == sizeof(void*)
&& offsetof(ZSTD_rust_initCCtxState, zero) == 2 * sizeof(void*)
&& offsetof(ZSTD_rust_initCCtxState, setCustomMem)
== 3 * sizeof(void*)
&& offsetof(ZSTD_rust_initCCtxState, setBmi2) == 4 * sizeof(void*)
&& offsetof(ZSTD_rust_initCCtxState, reset) == 5 * sizeof(void*)
&& sizeof(ZSTD_rust_initCCtxState) == 6 * sizeof(void*))
? 1 : -1];
typedef void* (*ZSTD_rust_initStaticCCtxInit_f)(void* context);
typedef struct {
void* callbackContext;
@@ -3149,16 +3172,28 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
}
static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
static void ZSTD_initCCtx_zero(void* context)
{
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
assert(cctx != NULL);
ZSTD_memset(cctx, 0, sizeof(*cctx));
cctx->customMem = memManager;
}
static void ZSTD_initCCtx_setCustomMem(void* context, const void* customMem)
{
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
cctx->customMem = *(const ZSTD_customMem*)customMem;
}
static void ZSTD_initCCtx_setBmi2(void* context)
{
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
cctx->bmi2 = ZSTD_cpuSupportsBmi2();
{ size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
assert(!ZSTD_isError(err));
(void)err;
}
}
static size_t ZSTD_initCCtx_reset(void* context)
{
return ZSTD_CCtx_reset((ZSTD_CCtx*)context, ZSTD_reset_parameters);
}
static int ZSTD_rust_createCCtx_validateCustomMem(void* context)
@@ -3174,7 +3209,17 @@ static void* ZSTD_rust_createCCtx_allocate(void* context, size_t size)
static void ZSTD_rust_createCCtx_init(void* context, void* cctx)
{
ZSTD_initCCtx((ZSTD_CCtx*)cctx, *(const ZSTD_customMem*)context);
ZSTD_rust_initCCtxState state;
state.callbackContext = cctx;
state.customMem = context;
state.zero = ZSTD_initCCtx_zero;
state.setCustomMem = ZSTD_initCCtx_setCustomMem;
state.setBmi2 = ZSTD_initCCtx_setBmi2;
state.reset = ZSTD_initCCtx_reset;
{ size_t const err = ZSTD_rust_initCCtx(&state);
assert(!ZSTD_isError(err));
(void)err;
}
}
ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
+134
View File
@@ -2120,6 +2120,61 @@ pub unsafe extern "C" fn ZSTD_rust_refThreadPool(
0
}
type InitCCtxCallbackFn = unsafe extern "C" fn(*mut c_void);
type InitCCtxSetCustomMemFn = unsafe extern "C" fn(*mut c_void, *const c_void);
type InitCCtxResetFn = unsafe extern "C" fn(*mut c_void) -> usize;
/// Explicit projection for private heap-CCtx initialization.
///
/// Rust owns the initialization ordering while C retains the private context
/// layout, allocator publication, CPU-feature query, and reset operation
/// behind callbacks.
#[repr(C)]
pub struct ZSTD_rust_initCCtxState {
callback_context: *mut c_void,
custom_mem: *const c_void,
zero: InitCCtxCallbackFn,
set_custom_mem: InitCCtxSetCustomMemFn,
set_bmi2: InitCCtxCallbackFn,
reset: InitCCtxResetFn,
}
const _: () = {
assert!(size_of::<InitCCtxCallbackFn>() == size_of::<usize>());
assert!(size_of::<InitCCtxSetCustomMemFn>() == size_of::<usize>());
assert!(size_of::<InitCCtxResetFn>() == size_of::<usize>());
assert!(offset_of!(ZSTD_rust_initCCtxState, callback_context) == 0);
assert!(offset_of!(ZSTD_rust_initCCtxState, custom_mem) == size_of::<usize>());
assert!(offset_of!(ZSTD_rust_initCCtxState, zero) == 2 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_initCCtxState, set_custom_mem) == 3 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_initCCtxState, set_bmi2) == 4 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_initCCtxState, reset) == 5 * size_of::<usize>());
assert!(size_of::<ZSTD_rust_initCCtxState>() == 6 * size_of::<usize>());
};
/// Initialize a heap-owned C compression context in the original order.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_initCCtx(state: *const ZSTD_rust_initCCtxState) -> usize {
if state.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let state = unsafe { &*state };
if state.callback_context.is_null() || state.custom_mem.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
unsafe {
(state.zero)(state.callback_context);
(state.set_custom_mem)(state.callback_context, state.custom_mem);
(state.set_bmi2)(state.callback_context);
let result = (state.reset)(state.callback_context);
if ERR_isError(result) {
return result;
}
}
0
}
type CreateCCtxValidateCustomMemFn = unsafe extern "C" fn(*mut c_void) -> c_int;
type CreateCCtxAllocateFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
type CreateCCtxInitFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
@@ -17745,6 +17800,85 @@ mod tests {
assert!(context.initialized.is_null());
}
#[derive(Default)]
struct InitCCtxTestContext {
events: Vec<&'static str>,
reset_result: usize,
}
unsafe fn init_cctx_test_context(context: *mut c_void) -> &'static mut InitCCtxTestContext {
unsafe { &mut *context.cast::<InitCCtxTestContext>() }
}
unsafe extern "C" fn init_cctx_test_zero(context: *mut c_void) {
unsafe { init_cctx_test_context(context) }
.events
.push("zero");
}
unsafe extern "C" fn init_cctx_test_set_custom_mem(
context: *mut c_void,
_custom_mem: *const c_void,
) {
unsafe { init_cctx_test_context(context) }
.events
.push("set-custom-mem");
}
unsafe extern "C" fn init_cctx_test_set_bmi2(context: *mut c_void) {
unsafe { init_cctx_test_context(context) }
.events
.push("set-bmi2");
}
unsafe extern "C" fn init_cctx_test_reset(context: *mut c_void) -> usize {
let context = unsafe { init_cctx_test_context(context) };
context.events.push("reset");
context.reset_result
}
fn init_cctx_test_state(context: &mut InitCCtxTestContext) -> ZSTD_rust_initCCtxState {
ZSTD_rust_initCCtxState {
callback_context: (context as *mut InitCCtxTestContext).cast(),
custom_mem: ptr::dangling(),
zero: init_cctx_test_zero,
set_custom_mem: init_cctx_test_set_custom_mem,
set_bmi2: init_cctx_test_set_bmi2,
reset: init_cctx_test_reset,
}
}
#[test]
fn init_cctx_runs_private_initialization_steps_in_order() {
let mut context = InitCCtxTestContext::default();
let state = init_cctx_test_state(&mut context);
let result = unsafe { ZSTD_rust_initCCtx(&state) };
assert_eq!(result, 0);
assert_eq!(
context.events,
["zero", "set-custom-mem", "set-bmi2", "reset"]
);
}
#[test]
fn init_cctx_propagates_reset_errors_after_initialization_steps() {
let mut context = InitCCtxTestContext {
reset_result: ERROR(ZstdErrorCode::MemoryAllocation),
..Default::default()
};
let state = init_cctx_test_state(&mut context);
let result = unsafe { ZSTD_rust_initCCtx(&state) };
assert_eq!(result, ERROR(ZstdErrorCode::MemoryAllocation));
assert_eq!(
context.events,
["zero", "set-custom-mem", "set-bmi2", "reset"]
);
}
#[derive(Default)]
struct InitStaticCCtxTestContext {
events: Vec<&'static str>,