feat(compress): split static CCtx construction callbacks
Move static CCtx construction sequencing out of the monolithic C leaf. Rust now validates the existing public workspace contract, sequences workspace creation, CCtx and auxiliary reservations, publication, and BMI2 setup, and short-circuits callback-reported failures. C callbacks retain the private cwksp and CCtx layouts plus the native workspace-size and CPU-feature rules. Add matching ABI layout assertions and focused callback-order, reservation- failure, workspace-capacity, and NULL-path unit coverage. Static-CDict and heap-CCtx paths remain unchanged. Test Plan: - `rustfmt --edition 2021 --check rust/src/zstd_compress.rs` -- passed - GCC and Clang `-fsyntax-only` checks on `zstd_compress.c` -- passed - GCC syntax checks with `ZSTD_DISABLE_ASM=1` and `ZSTD_ADDRESS_SANITIZER=1` -- passed - `git diff --check` -- passed - Cargo, make, native suites, and fuzzers not run per request
This commit is contained in:
+123
-22
@@ -363,13 +363,29 @@ typedef char ZSTD_rust_init_cctx_state_layout[
|
|||||||
&& offsetof(ZSTD_rust_initCCtxState, reset) == 5 * sizeof(void*)
|
&& offsetof(ZSTD_rust_initCCtxState, reset) == 5 * sizeof(void*)
|
||||||
&& sizeof(ZSTD_rust_initCCtxState) == 6 * sizeof(void*))
|
&& sizeof(ZSTD_rust_initCCtxState) == 6 * sizeof(void*))
|
||||||
? 1 : -1];
|
? 1 : -1];
|
||||||
typedef void* (*ZSTD_rust_initStaticCCtxInit_f)(void* context);
|
typedef void (*ZSTD_rust_initStaticCCtxCreateWorkspace_f)(void* context);
|
||||||
|
typedef void* (*ZSTD_rust_initStaticCCtxReserveObject_f)(void* context);
|
||||||
|
typedef void (*ZSTD_rust_initStaticCCtxZero_f)(void* context, void* cctx);
|
||||||
|
typedef void (*ZSTD_rust_initStaticCCtxMoveWorkspace_f)(
|
||||||
|
void* context, void* cctx);
|
||||||
|
typedef int (*ZSTD_rust_initStaticCCtxCheckAvailable_f)(void* context);
|
||||||
|
typedef void* (*ZSTD_rust_initStaticCCtxReserveBlockState_f)(
|
||||||
|
void* context, int blockState);
|
||||||
|
typedef void* (*ZSTD_rust_initStaticCCtxReserveTmpWorkspace_f)(void* context);
|
||||||
|
typedef void (*ZSTD_rust_initStaticCCtxSetBmi2_f)(void* context);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* callbackContext;
|
void* callbackContext;
|
||||||
void* workspace;
|
void* workspace;
|
||||||
size_t workspaceSize;
|
size_t workspaceSize;
|
||||||
size_t cctxSize;
|
size_t cctxSize;
|
||||||
ZSTD_rust_initStaticCCtxInit_f init;
|
ZSTD_rust_initStaticCCtxCreateWorkspace_f createWorkspace;
|
||||||
|
ZSTD_rust_initStaticCCtxReserveObject_f reserveObject;
|
||||||
|
ZSTD_rust_initStaticCCtxZero_f zero;
|
||||||
|
ZSTD_rust_initStaticCCtxMoveWorkspace_f moveWorkspace;
|
||||||
|
ZSTD_rust_initStaticCCtxCheckAvailable_f checkAvailable;
|
||||||
|
ZSTD_rust_initStaticCCtxReserveBlockState_f reserveBlockState;
|
||||||
|
ZSTD_rust_initStaticCCtxReserveTmpWorkspace_f reserveTmpWorkspace;
|
||||||
|
ZSTD_rust_initStaticCCtxSetBmi2_f setBmi2;
|
||||||
} ZSTD_rust_initStaticCCtxState;
|
} ZSTD_rust_initStaticCCtxState;
|
||||||
void* ZSTD_rust_initStaticCCtx(const ZSTD_rust_initStaticCCtxState* state);
|
void* ZSTD_rust_initStaticCCtx(const ZSTD_rust_initStaticCCtxState* state);
|
||||||
typedef char ZSTD_rust_init_static_cctx_state_layout[
|
typedef char ZSTD_rust_init_static_cctx_state_layout[
|
||||||
@@ -380,9 +396,23 @@ typedef char ZSTD_rust_init_static_cctx_state_layout[
|
|||||||
== 2 * sizeof(void*)
|
== 2 * sizeof(void*)
|
||||||
&& offsetof(ZSTD_rust_initStaticCCtxState, cctxSize)
|
&& offsetof(ZSTD_rust_initStaticCCtxState, cctxSize)
|
||||||
== 3 * sizeof(void*)
|
== 3 * sizeof(void*)
|
||||||
&& offsetof(ZSTD_rust_initStaticCCtxState, init)
|
&& offsetof(ZSTD_rust_initStaticCCtxState, createWorkspace)
|
||||||
== 4 * sizeof(void*)
|
== 4 * sizeof(void*)
|
||||||
&& sizeof(ZSTD_rust_initStaticCCtxState) == 5 * sizeof(void*))
|
&& offsetof(ZSTD_rust_initStaticCCtxState, reserveObject)
|
||||||
|
== 5 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, zero)
|
||||||
|
== 6 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, moveWorkspace)
|
||||||
|
== 7 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, checkAvailable)
|
||||||
|
== 8 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, reserveBlockState)
|
||||||
|
== 9 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, reserveTmpWorkspace)
|
||||||
|
== 10 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_initStaticCCtxState, setBmi2)
|
||||||
|
== 11 * sizeof(void*)
|
||||||
|
&& sizeof(ZSTD_rust_initStaticCCtxState) == 12 * sizeof(void*))
|
||||||
? 1 : -1];
|
? 1 : -1];
|
||||||
typedef void* (*ZSTD_rust_createCDictCreate_f)(
|
typedef void* (*ZSTD_rust_createCDictCreate_f)(
|
||||||
void* context, const void* dict, size_t dictSize,
|
void* context, const void* dict, size_t dictSize,
|
||||||
@@ -3347,32 +3377,93 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
void* workspace;
|
void* workspace;
|
||||||
size_t workspaceSize;
|
size_t workspaceSize;
|
||||||
|
ZSTD_cwksp workspaceState;
|
||||||
|
ZSTD_CCtx* cctx;
|
||||||
} ZSTD_rust_initStaticCCtxContext;
|
} ZSTD_rust_initStaticCCtxContext;
|
||||||
|
|
||||||
static void* ZSTD_rust_initStaticCCtx_init(void* opaque)
|
static void ZSTD_rust_initStaticCCtx_createWorkspace(void* opaque)
|
||||||
{
|
{
|
||||||
ZSTD_rust_initStaticCCtxContext* const context =
|
ZSTD_rust_initStaticCCtxContext* const context =
|
||||||
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
ZSTD_cwksp ws;
|
ZSTD_cwksp_init(&context->workspaceState, context->workspace,
|
||||||
ZSTD_CCtx* cctx;
|
context->workspaceSize,
|
||||||
|
|
||||||
ZSTD_cwksp_init(&ws, context->workspace, context->workspaceSize,
|
|
||||||
ZSTD_cwksp_static_alloc);
|
ZSTD_cwksp_static_alloc);
|
||||||
cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
|
}
|
||||||
if (cctx == NULL) return NULL;
|
|
||||||
|
|
||||||
|
static void* ZSTD_rust_initStaticCCtx_reserveObject(void* opaque)
|
||||||
|
{
|
||||||
|
ZSTD_rust_initStaticCCtxContext* const context =
|
||||||
|
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
|
context->cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(
|
||||||
|
&context->workspaceState, sizeof(ZSTD_CCtx));
|
||||||
|
return context->cctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTD_rust_initStaticCCtx_zero(void* opaque, void* cctx)
|
||||||
|
{
|
||||||
|
(void)opaque;
|
||||||
ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
|
ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
|
||||||
ZSTD_cwksp_move(&cctx->workspace, &ws);
|
}
|
||||||
cctx->staticSize = context->workspaceSize;
|
|
||||||
|
|
||||||
/* statically sized space. tmpWorkspace never moves (but prev/next block swap places) */
|
static void ZSTD_rust_initStaticCCtx_moveWorkspace(void* opaque, void* cctx)
|
||||||
if (!ZSTD_cwksp_check_available(&cctx->workspace, TMP_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
|
{
|
||||||
cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
|
ZSTD_rust_initStaticCCtxContext* const context =
|
||||||
cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
|
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
cctx->tmpWorkspace = ZSTD_cwksp_reserve_object(&cctx->workspace, TMP_WORKSPACE_SIZE);
|
ZSTD_CCtx* const contextCCtx = (ZSTD_CCtx*)cctx;
|
||||||
cctx->tmpWkspSize = TMP_WORKSPACE_SIZE;
|
ZSTD_cwksp_move(&contextCCtx->workspace, &context->workspaceState);
|
||||||
cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
contextCCtx->staticSize = context->workspaceSize;
|
||||||
return cctx;
|
}
|
||||||
|
|
||||||
|
static int ZSTD_rust_initStaticCCtx_checkAvailable(void* opaque)
|
||||||
|
{
|
||||||
|
ZSTD_rust_initStaticCCtxContext const* const context =
|
||||||
|
(const ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
|
return ZSTD_cwksp_check_available(
|
||||||
|
&context->cctx->workspace,
|
||||||
|
TMP_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ZSTD_RUST_INIT_STATIC_CCTX_PREV_CBLOCK = 0,
|
||||||
|
ZSTD_RUST_INIT_STATIC_CCTX_NEXT_CBLOCK = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static void* ZSTD_rust_initStaticCCtx_reserveBlockState(
|
||||||
|
void* opaque, int blockState)
|
||||||
|
{
|
||||||
|
ZSTD_rust_initStaticCCtxContext* const context =
|
||||||
|
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
|
void* const block = ZSTD_cwksp_reserve_object(
|
||||||
|
&context->cctx->workspace,
|
||||||
|
sizeof(ZSTD_compressedBlockState_t));
|
||||||
|
if (blockState == ZSTD_RUST_INIT_STATIC_CCTX_PREV_CBLOCK) {
|
||||||
|
context->cctx->blockState.prevCBlock =
|
||||||
|
(ZSTD_compressedBlockState_t*)block;
|
||||||
|
} else if (blockState == ZSTD_RUST_INIT_STATIC_CCTX_NEXT_CBLOCK) {
|
||||||
|
context->cctx->blockState.nextCBlock =
|
||||||
|
(ZSTD_compressedBlockState_t*)block;
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* ZSTD_rust_initStaticCCtx_reserveTmpWorkspace(void* opaque)
|
||||||
|
{
|
||||||
|
ZSTD_rust_initStaticCCtxContext* const context =
|
||||||
|
(ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
|
context->cctx->tmpWorkspace = ZSTD_cwksp_reserve_object(
|
||||||
|
&context->cctx->workspace, TMP_WORKSPACE_SIZE);
|
||||||
|
context->cctx->tmpWkspSize = TMP_WORKSPACE_SIZE;
|
||||||
|
return context->cctx->tmpWorkspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTD_rust_initStaticCCtx_setBmi2(void* opaque)
|
||||||
|
{
|
||||||
|
ZSTD_rust_initStaticCCtxContext const* const context =
|
||||||
|
(const ZSTD_rust_initStaticCCtxContext*)opaque;
|
||||||
|
context->cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
|
ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
|
||||||
@@ -3385,10 +3476,20 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
|
|||||||
state.workspace = workspace;
|
state.workspace = workspace;
|
||||||
state.workspaceSize = workspaceSize;
|
state.workspaceSize = workspaceSize;
|
||||||
state.cctxSize = sizeof(ZSTD_CCtx);
|
state.cctxSize = sizeof(ZSTD_CCtx);
|
||||||
state.init = ZSTD_rust_initStaticCCtx_init;
|
state.createWorkspace = ZSTD_rust_initStaticCCtx_createWorkspace;
|
||||||
|
state.reserveObject = ZSTD_rust_initStaticCCtx_reserveObject;
|
||||||
|
state.zero = ZSTD_rust_initStaticCCtx_zero;
|
||||||
|
state.moveWorkspace = ZSTD_rust_initStaticCCtx_moveWorkspace;
|
||||||
|
state.checkAvailable = ZSTD_rust_initStaticCCtx_checkAvailable;
|
||||||
|
state.reserveBlockState = ZSTD_rust_initStaticCCtx_reserveBlockState;
|
||||||
|
state.reserveTmpWorkspace = ZSTD_rust_initStaticCCtx_reserveTmpWorkspace;
|
||||||
|
state.setBmi2 = ZSTD_rust_initStaticCCtx_setBmi2;
|
||||||
return (ZSTD_CCtx*)ZSTD_rust_initStaticCCtx(&state);
|
return (ZSTD_CCtx*)ZSTD_rust_initStaticCCtx(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Keep the private workspace and CCtx layout operations above in C. Rust
|
||||||
|
* owns only the public checks, construction order, and failure policy. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears and frees all of the dictionaries in the CCtx.
|
* Clears and frees all of the dictionaries in the CCtx.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+330
-54
@@ -2351,33 +2351,68 @@ pub unsafe extern "C" fn ZSTD_rust_createCDictAdvancedWrapper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type InitStaticCCtxFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void;
|
type InitStaticCCtxCreateWorkspaceFn = unsafe extern "C" fn(*mut c_void);
|
||||||
|
type InitStaticCCtxReserveObjectFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void;
|
||||||
|
type InitStaticCCtxZeroFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
||||||
|
type InitStaticCCtxMoveWorkspaceFn = unsafe extern "C" fn(*mut c_void, *mut c_void);
|
||||||
|
type InitStaticCCtxCheckAvailableFn = unsafe extern "C" fn(*mut c_void) -> c_int;
|
||||||
|
type InitStaticCCtxReserveBlockStateFn = unsafe extern "C" fn(*mut c_void, c_int) -> *mut c_void;
|
||||||
|
type InitStaticCCtxReserveTmpWorkspaceFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void;
|
||||||
|
type InitStaticCCtxSetBmi2Fn = unsafe extern "C" fn(*mut c_void);
|
||||||
const ZSTD_STATIC_WORKSPACE_ALIGNMENT: usize = 8;
|
const ZSTD_STATIC_WORKSPACE_ALIGNMENT: usize = 8;
|
||||||
|
const INIT_STATIC_CCTX_PREV_CBLOCK: c_int = 0;
|
||||||
|
const INIT_STATIC_CCTX_NEXT_CBLOCK: c_int = 1;
|
||||||
|
|
||||||
/// Explicit projection for the public `ZSTD_initStaticCCtx` wrapper.
|
/// Explicit projection for the public `ZSTD_initStaticCCtx` wrapper.
|
||||||
///
|
///
|
||||||
/// Rust owns workspace pointer/alignment validation, minimum-size validation,
|
/// Rust owns workspace pointer/alignment validation, minimum-size validation,
|
||||||
/// and callback ordering. C retains the private static-workspace layout and
|
/// construction ordering, and callback failure policy. C retains the private
|
||||||
/// context initialization behind one callback.
|
/// static-workspace and CCtx layout operations behind narrow callbacks.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ZSTD_rust_initStaticCCtxState {
|
pub struct ZSTD_rust_initStaticCCtxState {
|
||||||
callback_context: *mut c_void,
|
callback_context: *mut c_void,
|
||||||
workspace: *mut c_void,
|
workspace: *mut c_void,
|
||||||
workspace_size: usize,
|
workspace_size: usize,
|
||||||
cctx_size: usize,
|
cctx_size: usize,
|
||||||
init: InitStaticCCtxFn,
|
create_workspace: InitStaticCCtxCreateWorkspaceFn,
|
||||||
|
reserve_object: InitStaticCCtxReserveObjectFn,
|
||||||
|
zero: InitStaticCCtxZeroFn,
|
||||||
|
move_workspace: InitStaticCCtxMoveWorkspaceFn,
|
||||||
|
check_available: InitStaticCCtxCheckAvailableFn,
|
||||||
|
reserve_block_state: InitStaticCCtxReserveBlockStateFn,
|
||||||
|
reserve_tmp_workspace: InitStaticCCtxReserveTmpWorkspaceFn,
|
||||||
|
set_bmi2: InitStaticCCtxSetBmi2Fn,
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = {
|
const _: () = {
|
||||||
|
assert!(size_of::<InitStaticCCtxCreateWorkspaceFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxReserveObjectFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxZeroFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxMoveWorkspaceFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxCheckAvailableFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxReserveBlockStateFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxReserveTmpWorkspaceFn>() == size_of::<usize>());
|
||||||
|
assert!(size_of::<InitStaticCCtxSetBmi2Fn>() == size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, callback_context) == 0);
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, callback_context) == 0);
|
||||||
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, workspace) == size_of::<usize>());
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, workspace) == size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, workspace_size) == 2 * size_of::<usize>());
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, workspace_size) == 2 * size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, cctx_size) == 3 * size_of::<usize>());
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, cctx_size) == 3 * size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, init) == 4 * size_of::<usize>());
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, create_workspace) == 4 * size_of::<usize>());
|
||||||
assert!(size_of::<ZSTD_rust_initStaticCCtxState>() == size_of::<[usize; 5]>());
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, reserve_object) == 5 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, zero) == 6 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, move_workspace) == 7 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, check_available) == 8 * size_of::<usize>());
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_initStaticCCtxState, reserve_block_state) == 9 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_initStaticCCtxState, reserve_tmp_workspace) == 10 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(offset_of!(ZSTD_rust_initStaticCCtxState, set_bmi2) == 11 * size_of::<usize>());
|
||||||
|
assert!(size_of::<ZSTD_rust_initStaticCCtxState>() == size_of::<[usize; 12]>());
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Validate static CCtx workspace ownership before entering the C leaf.
|
/// Validate and sequence static CCtx construction before entering C leaves.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn ZSTD_rust_initStaticCCtx(
|
pub unsafe extern "C" fn ZSTD_rust_initStaticCCtx(
|
||||||
state: *const ZSTD_rust_initStaticCCtxState,
|
state: *const ZSTD_rust_initStaticCCtxState,
|
||||||
@@ -2393,7 +2428,33 @@ pub unsafe extern "C" fn ZSTD_rust_initStaticCCtx(
|
|||||||
{
|
{
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
unsafe { (state.init)(state.callback_context) }
|
unsafe {
|
||||||
|
(state.create_workspace)(state.callback_context);
|
||||||
|
let cctx = (state.reserve_object)(state.callback_context);
|
||||||
|
if cctx.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
(state.zero)(state.callback_context, cctx);
|
||||||
|
(state.move_workspace)(state.callback_context, cctx);
|
||||||
|
if (state.check_available)(state.callback_context) == 0 {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
if (state.reserve_block_state)(state.callback_context, INIT_STATIC_CCTX_PREV_CBLOCK)
|
||||||
|
.is_null()
|
||||||
|
{
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
if (state.reserve_block_state)(state.callback_context, INIT_STATIC_CCTX_NEXT_CBLOCK)
|
||||||
|
.is_null()
|
||||||
|
{
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
if (state.reserve_tmp_workspace)(state.callback_context).is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
(state.set_bmi2)(state.callback_context);
|
||||||
|
cctx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FreeCCtxContentFn = unsafe extern "C" fn(*mut c_void);
|
type FreeCCtxContentFn = unsafe extern "C" fn(*mut c_void);
|
||||||
@@ -18444,13 +18505,84 @@ mod tests {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct InitStaticCCtxTestContext {
|
struct InitStaticCCtxTestContext {
|
||||||
events: Vec<&'static str>,
|
events: Vec<&'static str>,
|
||||||
result: *mut c_void,
|
reserved_cctx: *mut c_void,
|
||||||
|
check_available_result: c_int,
|
||||||
|
reserve_block_state_failure: Option<usize>,
|
||||||
|
reserve_block_state_count: usize,
|
||||||
|
reserve_tmp_workspace_result: *mut c_void,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn init_static_cctx_test_init(context: *mut c_void) -> *mut c_void {
|
unsafe fn init_static_cctx_test_context(
|
||||||
|
context: *mut c_void,
|
||||||
|
) -> &'static mut InitStaticCCtxTestContext {
|
||||||
|
unsafe { &mut *context.cast::<InitStaticCCtxTestContext>() }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_create_workspace(context: *mut c_void) {
|
||||||
|
unsafe { init_static_cctx_test_context(context) }
|
||||||
|
.events
|
||||||
|
.push("create-workspace");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_reserve_object(context: *mut c_void) -> *mut c_void {
|
||||||
|
let context = unsafe { init_static_cctx_test_context(context) };
|
||||||
|
context.events.push("reserve-object");
|
||||||
|
context.reserved_cctx
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_zero(context: *mut c_void, _cctx: *mut c_void) {
|
||||||
|
unsafe { init_static_cctx_test_context(context) }
|
||||||
|
.events
|
||||||
|
.push("zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_move_workspace(
|
||||||
|
context: *mut c_void,
|
||||||
|
_cctx: *mut c_void,
|
||||||
|
) {
|
||||||
|
unsafe { init_static_cctx_test_context(context) }
|
||||||
|
.events
|
||||||
|
.push("move-workspace");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_check_available(context: *mut c_void) -> c_int {
|
||||||
|
let context = unsafe { init_static_cctx_test_context(context) };
|
||||||
|
context.events.push("check-available");
|
||||||
|
context.check_available_result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_reserve_block_state(
|
||||||
|
context: *mut c_void,
|
||||||
|
block_state: c_int,
|
||||||
|
) -> *mut c_void {
|
||||||
let context = unsafe { &mut *context.cast::<InitStaticCCtxTestContext>() };
|
let context = unsafe { &mut *context.cast::<InitStaticCCtxTestContext>() };
|
||||||
context.events.push("init");
|
context.events.push(match block_state {
|
||||||
context.result
|
INIT_STATIC_CCTX_PREV_CBLOCK => "reserve-prev-block-state",
|
||||||
|
INIT_STATIC_CCTX_NEXT_CBLOCK => "reserve-next-block-state",
|
||||||
|
_ => "reserve-unknown-block-state",
|
||||||
|
});
|
||||||
|
let result =
|
||||||
|
if context.reserve_block_state_failure == Some(context.reserve_block_state_count) {
|
||||||
|
ptr::null_mut()
|
||||||
|
} else {
|
||||||
|
ptr::dangling_mut()
|
||||||
|
};
|
||||||
|
context.reserve_block_state_count += 1;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_reserve_tmp_workspace(
|
||||||
|
context: *mut c_void,
|
||||||
|
) -> *mut c_void {
|
||||||
|
let context = unsafe { init_static_cctx_test_context(context) };
|
||||||
|
context.events.push("reserve-tmp-workspace");
|
||||||
|
context.reserve_tmp_workspace_result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn init_static_cctx_test_set_bmi2(context: *mut c_void) {
|
||||||
|
unsafe { init_static_cctx_test_context(context) }
|
||||||
|
.events
|
||||||
|
.push("set-bmi2");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_static_cctx_test_state(
|
fn init_static_cctx_test_state(
|
||||||
@@ -18464,50 +18596,23 @@ mod tests {
|
|||||||
workspace,
|
workspace,
|
||||||
workspace_size,
|
workspace_size,
|
||||||
cctx_size,
|
cctx_size,
|
||||||
init: init_static_cctx_test_init,
|
create_workspace: init_static_cctx_test_create_workspace,
|
||||||
|
reserve_object: init_static_cctx_test_reserve_object,
|
||||||
|
zero: init_static_cctx_test_zero,
|
||||||
|
move_workspace: init_static_cctx_test_move_workspace,
|
||||||
|
check_available: init_static_cctx_test_check_available,
|
||||||
|
reserve_block_state: init_static_cctx_test_reserve_block_state,
|
||||||
|
reserve_tmp_workspace: init_static_cctx_test_reserve_tmp_workspace,
|
||||||
|
set_bmi2: init_static_cctx_test_set_bmi2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init_static_cctx_rejects_an_unaligned_workspace_before_callback() {
|
fn init_static_cctx_runs_private_construction_steps_in_order() {
|
||||||
let mut context = InitStaticCCtxTestContext {
|
let mut context = InitStaticCCtxTestContext {
|
||||||
result: ptr::dangling_mut(),
|
reserved_cctx: ptr::dangling_mut(),
|
||||||
..Default::default()
|
check_available_result: 1,
|
||||||
};
|
reserve_tmp_workspace_result: ptr::dangling_mut(),
|
||||||
let mut workspace = [0usize; 2];
|
|
||||||
let unaligned_workspace = workspace.as_mut_ptr().cast::<u8>().wrapping_add(1).cast();
|
|
||||||
let state = init_static_cctx_test_state(&mut context, unaligned_workspace, usize::MAX, 0);
|
|
||||||
|
|
||||||
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
|
||||||
|
|
||||||
assert!(result.is_null());
|
|
||||||
assert!(context.events.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn init_static_cctx_rejects_a_small_workspace_before_callback() {
|
|
||||||
let mut context = InitStaticCCtxTestContext {
|
|
||||||
result: ptr::dangling_mut(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let mut workspace = [0usize; 1];
|
|
||||||
let state = init_static_cctx_test_state(
|
|
||||||
&mut context,
|
|
||||||
workspace.as_mut_ptr().cast(),
|
|
||||||
size_of_val(&workspace),
|
|
||||||
size_of_val(&workspace),
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
|
||||||
|
|
||||||
assert!(result.is_null());
|
|
||||||
assert!(context.events.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn init_static_cctx_calls_the_initializer_after_workspace_validation() {
|
|
||||||
let mut context = InitStaticCCtxTestContext {
|
|
||||||
result: ptr::dangling_mut(),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut workspace = [0usize; 1];
|
let mut workspace = [0usize; 1];
|
||||||
@@ -18520,14 +18625,155 @@ mod tests {
|
|||||||
|
|
||||||
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
assert_eq!(result, context.result);
|
assert_eq!(result, context.reserved_cctx);
|
||||||
assert_eq!(context.events, ["init"]);
|
assert_eq!(
|
||||||
|
context.events,
|
||||||
|
[
|
||||||
|
"create-workspace",
|
||||||
|
"reserve-object",
|
||||||
|
"zero",
|
||||||
|
"move-workspace",
|
||||||
|
"check-available",
|
||||||
|
"reserve-prev-block-state",
|
||||||
|
"reserve-next-block-state",
|
||||||
|
"reserve-tmp-workspace",
|
||||||
|
"set-bmi2",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_stops_after_cctx_reservation_failure() {
|
||||||
|
let mut context = InitStaticCCtxTestContext {
|
||||||
|
check_available_result: 1,
|
||||||
|
reserve_tmp_workspace_result: ptr::dangling_mut(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let mut workspace = [0usize; 1];
|
||||||
|
let state = init_static_cctx_test_state(
|
||||||
|
&mut context,
|
||||||
|
workspace.as_mut_ptr().cast(),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert_eq!(context.events, ["create-workspace", "reserve-object"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_stops_after_workspace_capacity_failure() {
|
||||||
|
let mut context = InitStaticCCtxTestContext {
|
||||||
|
reserved_cctx: ptr::dangling_mut(),
|
||||||
|
reserve_tmp_workspace_result: ptr::dangling_mut(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let mut workspace = [0usize; 1];
|
||||||
|
let state = init_static_cctx_test_state(
|
||||||
|
&mut context,
|
||||||
|
workspace.as_mut_ptr().cast(),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
size_of_val(&workspace) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert_eq!(
|
||||||
|
context.events,
|
||||||
|
[
|
||||||
|
"create-workspace",
|
||||||
|
"reserve-object",
|
||||||
|
"zero",
|
||||||
|
"move-workspace",
|
||||||
|
"check-available",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_stops_after_block_state_reservation_failure() {
|
||||||
|
let mut context = InitStaticCCtxTestContext {
|
||||||
|
reserved_cctx: ptr::dangling_mut(),
|
||||||
|
check_available_result: 1,
|
||||||
|
reserve_block_state_failure: Some(1),
|
||||||
|
reserve_tmp_workspace_result: ptr::dangling_mut(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let mut workspace = [0usize; 1];
|
||||||
|
let state = init_static_cctx_test_state(
|
||||||
|
&mut context,
|
||||||
|
workspace.as_mut_ptr().cast(),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
size_of_val(&workspace) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert_eq!(
|
||||||
|
context.events,
|
||||||
|
[
|
||||||
|
"create-workspace",
|
||||||
|
"reserve-object",
|
||||||
|
"zero",
|
||||||
|
"move-workspace",
|
||||||
|
"check-available",
|
||||||
|
"reserve-prev-block-state",
|
||||||
|
"reserve-next-block-state",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_stops_after_tmp_workspace_reservation_failure() {
|
||||||
|
let mut context = InitStaticCCtxTestContext {
|
||||||
|
reserved_cctx: ptr::dangling_mut(),
|
||||||
|
check_available_result: 1,
|
||||||
|
reserve_tmp_workspace_result: ptr::null_mut(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let mut workspace = [0usize; 1];
|
||||||
|
let state = init_static_cctx_test_state(
|
||||||
|
&mut context,
|
||||||
|
workspace.as_mut_ptr().cast(),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
size_of_val(&workspace) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert_eq!(
|
||||||
|
context.events,
|
||||||
|
[
|
||||||
|
"create-workspace",
|
||||||
|
"reserve-object",
|
||||||
|
"zero",
|
||||||
|
"move-workspace",
|
||||||
|
"check-available",
|
||||||
|
"reserve-prev-block-state",
|
||||||
|
"reserve-next-block-state",
|
||||||
|
"reserve-tmp-workspace",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_rejects_a_null_state() {
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(ptr::null()) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init_static_cctx_rejects_a_null_workspace() {
|
fn init_static_cctx_rejects_a_null_workspace() {
|
||||||
let mut context = InitStaticCCtxTestContext {
|
let mut context = InitStaticCCtxTestContext {
|
||||||
result: ptr::dangling_mut(),
|
reserved_cctx: ptr::dangling_mut(),
|
||||||
|
check_available_result: 1,
|
||||||
|
reserve_tmp_workspace_result: ptr::dangling_mut(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let state = init_static_cctx_test_state(&mut context, ptr::null_mut(), usize::MAX, 0);
|
let state = init_static_cctx_test_state(&mut context, ptr::null_mut(), usize::MAX, 0);
|
||||||
@@ -18538,6 +18784,36 @@ mod tests {
|
|||||||
assert!(context.events.is_empty());
|
assert!(context.events.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_rejects_an_unaligned_workspace_before_callback() {
|
||||||
|
let mut context = InitStaticCCtxTestContext::default();
|
||||||
|
let mut workspace = [0usize; 2];
|
||||||
|
let unaligned_workspace = workspace.as_mut_ptr().cast::<u8>().wrapping_add(1).cast();
|
||||||
|
let state = init_static_cctx_test_state(&mut context, unaligned_workspace, usize::MAX, 0);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert!(context.events.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_static_cctx_rejects_a_small_workspace_before_callback() {
|
||||||
|
let mut context = InitStaticCCtxTestContext::default();
|
||||||
|
let mut workspace = [0usize; 1];
|
||||||
|
let state = init_static_cctx_test_state(
|
||||||
|
&mut context,
|
||||||
|
workspace.as_mut_ptr().cast(),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
size_of_val(&workspace),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_initStaticCCtx(&state) };
|
||||||
|
|
||||||
|
assert!(result.is_null());
|
||||||
|
assert!(context.events.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct FreeCCtxTestContext {
|
struct FreeCCtxTestContext {
|
||||||
events: Vec<&'static str>,
|
events: Vec<&'static str>,
|
||||||
|
|||||||
Reference in New Issue
Block a user