refactor(dict): move advanced-CDict copy policy to Rust
Keep the opaque ZSTD_CCtx_params copy operation in C, but make Rust own the public advanced2 null-source validation and copy-before-preparation ordering. The bridge now rejects a missing source before any allocator or workspace callback, with explicit ABI assertions and focused order/null-input tests. Test Plan: Not run in this atomic commit; the capped serial Rust, native, smoke, and original test-suite verification follows.
This commit is contained in:
@@ -2910,6 +2910,8 @@ typedef void (*ZSTD_rust_createCDictAdvancedFreeWorkspace_f)(
|
||||
void* context, void* workspace);
|
||||
typedef void (*ZSTD_rust_createCDictAdvancedFree_f)(
|
||||
void* context, void* cdict);
|
||||
typedef void (*ZSTD_rust_createCDictAdvancedCopyParams_f)(
|
||||
void* context, void* destination, const void* source);
|
||||
typedef struct {
|
||||
void* callbackContext;
|
||||
ZSTD_CCtx_params* cctxParams;
|
||||
@@ -2928,6 +2930,8 @@ typedef struct {
|
||||
ZSTD_rust_createCDictAdvancedInit_f init;
|
||||
ZSTD_rust_createCDictAdvancedFreeWorkspace_f freeWorkspace;
|
||||
ZSTD_rust_createCDictAdvancedFree_f free;
|
||||
const void* originalCctxParams;
|
||||
ZSTD_rust_createCDictAdvancedCopyParams_f copyParams;
|
||||
} ZSTD_rust_createCDictAdvancedState;
|
||||
void* ZSTD_rust_createCDictAdvanced(
|
||||
const ZSTD_rust_createCDictAdvancedState* state,
|
||||
@@ -2967,8 +2971,12 @@ typedef char ZSTD_rust_create_cdict_advanced_state_layout[
|
||||
== 13 * sizeof(void*) + 2 * sizeof(U32)
|
||||
&& offsetof(ZSTD_rust_createCDictAdvancedState, free)
|
||||
== 14 * sizeof(void*) + 2 * sizeof(U32)
|
||||
&& offsetof(ZSTD_rust_createCDictAdvancedState, originalCctxParams)
|
||||
== 15 * sizeof(void*) + 2 * sizeof(U32)
|
||||
&& offsetof(ZSTD_rust_createCDictAdvancedState, copyParams)
|
||||
== 16 * sizeof(void*) + 2 * sizeof(U32)
|
||||
&& sizeof(ZSTD_rust_createCDictAdvancedState)
|
||||
== 15 * sizeof(void*) + 2 * sizeof(U32))
|
||||
== 17 * sizeof(void*) + 2 * sizeof(U32))
|
||||
? 1 : -1];
|
||||
|
||||
typedef void (*ZSTD_rust_createCDictAdvancedWrapperInitParams_f)(
|
||||
@@ -7200,6 +7208,13 @@ static int ZSTD_rust_createCDictAdvanced_validateCustomMem(void* context)
|
||||
return ((!customMem->customAlloc) ^ (!customMem->customFree)) == 0;
|
||||
}
|
||||
|
||||
static void ZSTD_rust_createCDictAdvanced_copyParams(
|
||||
void* context, void* destination, const void* source)
|
||||
{
|
||||
(void)context;
|
||||
*(ZSTD_CCtx_params*)destination = *(const ZSTD_CCtx_params*)source;
|
||||
}
|
||||
|
||||
static void* ZSTD_rust_createCDictAdvanced_allocate(
|
||||
void* context, size_t workspaceSize)
|
||||
{
|
||||
@@ -7343,9 +7358,6 @@ ZSTD_CDict* ZSTD_createCDict_advanced2(
|
||||
};
|
||||
|
||||
DEBUGLOG(3, "ZSTD_createCDict_advanced2, dictSize=%u, mode=%u", (unsigned)dictSize, (unsigned)dictContentType);
|
||||
if (originalCctxParams == NULL) return NULL;
|
||||
|
||||
cctxParams = *originalCctxParams;
|
||||
context.customMem = customMem;
|
||||
state.callbackContext = &context;
|
||||
state.cctxParams = &cctxParams;
|
||||
@@ -7364,6 +7376,8 @@ ZSTD_CDict* ZSTD_createCDict_advanced2(
|
||||
state.init = ZSTD_rust_createCDictAdvanced_init;
|
||||
state.freeWorkspace = ZSTD_rust_createCDictAdvanced_freeWorkspace;
|
||||
state.free = ZSTD_rust_createCDictAdvanced_free;
|
||||
state.originalCctxParams = originalCctxParams;
|
||||
state.copyParams = ZSTD_rust_createCDictAdvanced_copyParams;
|
||||
return (ZSTD_CDict*)ZSTD_rust_createCDictAdvanced(
|
||||
&state, dict, dictSize,
|
||||
(int)dictLoadMethod, (int)dictContentType);
|
||||
|
||||
@@ -900,13 +900,16 @@ type CreateCDictAdvancedInitFn = unsafe extern "C" fn(
|
||||
) -> usize;
|
||||
type CreateCDictAdvancedFreeFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
||||
type CreateCDictAdvancedFreeWorkspaceFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
||||
type CreateCDictAdvancedCopyParamsFn =
|
||||
unsafe extern "C" fn(*mut c_void, *mut c_void, *const c_void);
|
||||
|
||||
/// Explicit projection for the public `ZSTD_createCDict_advanced2` wrapper.
|
||||
///
|
||||
/// Rust owns context-free parameter preparation, workspace-size policy,
|
||||
/// custom-memory validation, allocation, and callback ordering. C supplies
|
||||
/// the private layout-size inputs and retains workspace construction, CDict
|
||||
/// initialization, and teardown behind narrow callbacks.
|
||||
/// source-parameter validation/copy ordering, custom-memory validation,
|
||||
/// allocation, and callback ordering. C supplies the private layout-size
|
||||
/// inputs and retains workspace construction, CDict initialization, and
|
||||
/// teardown behind narrow callbacks.
|
||||
/// The pointer fields keep the private `ZSTD_CCtx_params` layout opaque here
|
||||
/// while allowing C to publish the fields selected by the Rust parameter leaf.
|
||||
#[repr(C)]
|
||||
@@ -928,6 +931,8 @@ pub struct ZSTD_rust_createCDictAdvancedState {
|
||||
init: CreateCDictAdvancedInitFn,
|
||||
free_workspace: CreateCDictAdvancedFreeWorkspaceFn,
|
||||
free: CreateCDictAdvancedFreeFn,
|
||||
original_cctx_params: *const c_void,
|
||||
copy_params: CreateCDictAdvancedCopyParamsFn,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
@@ -1002,9 +1007,17 @@ const _: () = {
|
||||
== size_of::<[usize; 14]>() + size_of::<[u32; 2]>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTD_rust_createCDictAdvancedState>()
|
||||
offset_of!(ZSTD_rust_createCDictAdvancedState, original_cctx_params)
|
||||
== size_of::<[usize; 15]>() + size_of::<[u32; 2]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_createCDictAdvancedState, copy_params)
|
||||
== size_of::<[usize; 16]>() + size_of::<[u32; 2]>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTD_rust_createCDictAdvancedState>()
|
||||
== size_of::<[usize; 17]>() + size_of::<[u32; 2]>()
|
||||
);
|
||||
};
|
||||
|
||||
/// Prepare advanced-CDict parameters and run the C-owned construction leaves
|
||||
@@ -1027,10 +1040,22 @@ pub unsafe extern "C" fn ZSTD_rust_createCDictAdvanced(
|
||||
|| state.enable_dedicated_dict_search.is_null()
|
||||
|| state.use_row_match_finder.is_null()
|
||||
|| state.sizing.is_null()
|
||||
|| state.original_cctx_params.is_null()
|
||||
{
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
// The source is opaque here: C retains the private parameter-layout copy,
|
||||
// while Rust owns rejecting a missing source and placing that copy before
|
||||
// parameter preparation and the allocation/initialization callbacks.
|
||||
unsafe {
|
||||
(state.copy_params)(
|
||||
state.callback_context,
|
||||
state.cctx_params.cast(),
|
||||
state.original_cctx_params,
|
||||
);
|
||||
}
|
||||
|
||||
let prepare_result = unsafe {
|
||||
crate::zstd_compress_params_api::ZSTD_rust_params_prepareAdvancedCDict(
|
||||
state.cctx_params,
|
||||
@@ -4842,11 +4867,24 @@ mod tests {
|
||||
init_dict_load_method: c_int,
|
||||
init_dict_content_type: c_int,
|
||||
init_cctx_params: *const ZSTD_CCtx_params,
|
||||
copied_destination: *mut c_void,
|
||||
copied_source: *const c_void,
|
||||
free_workspace: *mut c_void,
|
||||
free_cdict: *mut c_void,
|
||||
init_result: usize,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn create_cdict_advanced_test_copy_params(
|
||||
context: *mut c_void,
|
||||
destination: *mut c_void,
|
||||
source: *const c_void,
|
||||
) {
|
||||
let probe = unsafe { &mut *context.cast::<CreateCDictAdvancedProbe>() };
|
||||
probe.events.push("copy_params");
|
||||
probe.copied_destination = destination;
|
||||
probe.copied_source = source;
|
||||
}
|
||||
|
||||
unsafe extern "C" fn create_cdict_advanced_test_validate_custom_mem(
|
||||
context: *mut c_void,
|
||||
) -> c_int {
|
||||
@@ -5023,6 +5061,8 @@ mod tests {
|
||||
init: create_cdict_advanced_test_init,
|
||||
free_workspace: create_cdict_advanced_test_free_workspace,
|
||||
free: create_cdict_advanced_test_free,
|
||||
original_cctx_params: ptr::dangling(),
|
||||
copy_params: create_cdict_advanced_test_copy_params,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5077,6 +5117,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
probe.events,
|
||||
[
|
||||
"copy_params",
|
||||
"validate",
|
||||
"allocate",
|
||||
"create_workspace",
|
||||
@@ -5094,6 +5135,8 @@ mod tests {
|
||||
assert_eq!(probe.initialized_cdict, probe.cdict_result);
|
||||
assert_eq!(probe.use_row_match_finder, use_row_match_finder);
|
||||
assert_eq!(probe.init_cdict, probe.cdict_result);
|
||||
assert_eq!(probe.copied_destination, cctx_params.cast());
|
||||
assert_eq!(probe.copied_source, state.original_cctx_params);
|
||||
assert_eq!(probe.init_dict, dict.as_ptr().cast());
|
||||
assert_eq!(probe.init_dict_size, dict.len());
|
||||
assert_eq!(probe.init_dict_load_method, ZSTD_DLM_BY_REF);
|
||||
@@ -5124,7 +5167,7 @@ mod tests {
|
||||
};
|
||||
|
||||
assert!(result.is_null());
|
||||
assert_eq!(probe.events, ["validate"]);
|
||||
assert_eq!(probe.events, ["copy_params", "validate"]);
|
||||
assert!(probe.created_workspace.is_null());
|
||||
assert!(probe.free_workspace.is_null());
|
||||
assert!(probe.free_cdict.is_null());
|
||||
@@ -5154,7 +5197,7 @@ mod tests {
|
||||
};
|
||||
|
||||
assert!(result.is_null());
|
||||
assert_eq!(probe.events, ["validate", "allocate"]);
|
||||
assert_eq!(probe.events, ["copy_params", "validate", "allocate"]);
|
||||
assert_eq!(
|
||||
probe.allocated_workspace_size,
|
||||
create_cdict_advanced_expected_workspace_size(
|
||||
@@ -5170,6 +5213,33 @@ mod tests {
|
||||
assert!(probe.free_cdict.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_cdict_advanced_rejects_missing_source_params_before_copy() {
|
||||
let mut probe = CreateCDictAdvancedProbe::default();
|
||||
let mut params_storage = create_cdict_advanced_test_params();
|
||||
let cctx_params = params_storage.as_mut_ptr();
|
||||
let cparams = ZSTD_compressionParameters::default();
|
||||
let enable_dedicated_dict_search = 0;
|
||||
let use_row_match_finder = 0;
|
||||
let mut state = create_cdict_advanced_test_state(
|
||||
&mut probe,
|
||||
cctx_params,
|
||||
&cparams,
|
||||
&enable_dedicated_dict_search,
|
||||
&use_row_match_finder,
|
||||
);
|
||||
state.original_cctx_params = ptr::null();
|
||||
|
||||
let result = unsafe {
|
||||
ZSTD_rust_createCDictAdvanced(&state, ptr::null(), 0, ZSTD_DLM_BY_REF, ZSTD_DCT_AUTO)
|
||||
};
|
||||
|
||||
assert!(result.is_null());
|
||||
assert!(probe.events.is_empty());
|
||||
assert!(probe.copied_destination.is_null());
|
||||
assert!(probe.copied_source.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_cdict_advanced_frees_workspace_after_reservation_failure() {
|
||||
let workspace = ptr::dangling_mut::<c_void>();
|
||||
@@ -5206,6 +5276,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
probe.events,
|
||||
[
|
||||
"copy_params",
|
||||
"validate",
|
||||
"allocate",
|
||||
"create_workspace",
|
||||
@@ -5258,6 +5329,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
probe.events,
|
||||
[
|
||||
"copy_params",
|
||||
"validate",
|
||||
"allocate",
|
||||
"create_workspace",
|
||||
|
||||
Reference in New Issue
Block a user