refactor(compress): move end directive validation to Rust
Project the scalar ZSTD_compressStream2 end directive into Rust and keep C responsible for the private streaming context, existing parameter error, and diagnostic text. The Rust range policy preserves the original unsigned enum validation for continue, flush, and end. Test Plan: ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check; make -j1; ./tests/rustLibSmoke; make -j1 -C tests test (all shell tests, large streaming tests, native tester, fuzzer phases, and zstream tester passed).
This commit is contained in:
@@ -769,6 +769,15 @@ size_t ZSTD_compressStream2_c(ZSTD_CCtx* cctx,
|
|||||||
ZSTD_outBuffer* output,
|
ZSTD_outBuffer* output,
|
||||||
ZSTD_inBuffer* input,
|
ZSTD_inBuffer* input,
|
||||||
ZSTD_EndDirective endOp);
|
ZSTD_EndDirective endOp);
|
||||||
|
typedef struct {
|
||||||
|
int endOp;
|
||||||
|
} ZSTD_rust_compressStream2PolicyState;
|
||||||
|
int ZSTD_rust_compressStream2Policy(
|
||||||
|
const ZSTD_rust_compressStream2PolicyState* state);
|
||||||
|
typedef char ZSTD_rust_compress_stream2_policy_state_layout[
|
||||||
|
(offsetof(ZSTD_rust_compressStream2PolicyState, endOp) == 0
|
||||||
|
&& sizeof(ZSTD_rust_compressStream2PolicyState) == sizeof(int))
|
||||||
|
? 1 : -1];
|
||||||
int ZSTD_rust_simpleCompress2Level(const void* cctx, size_t srcSize);
|
int ZSTD_rust_simpleCompress2Level(const void* cctx, size_t srcSize);
|
||||||
typedef int (*ZSTD_rust_simpleCompress2Level_f)(const void* cctx, size_t srcSize);
|
typedef int (*ZSTD_rust_simpleCompress2Level_f)(const void* cctx, size_t srcSize);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -8266,7 +8275,10 @@ size_t ZSTD_compressStream2_c( ZSTD_CCtx* cctx,
|
|||||||
/* check conditions */
|
/* check conditions */
|
||||||
RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
|
RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
|
||||||
RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer");
|
RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer");
|
||||||
RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective");
|
{ ZSTD_rust_compressStream2PolicyState const state = {(int)endOp};
|
||||||
|
RETURN_ERROR_IF(!ZSTD_rust_compressStream2Policy(&state),
|
||||||
|
parameter_outOfBound, "invalid endDirective");
|
||||||
|
}
|
||||||
assert(cctx != NULL);
|
assert(cctx != NULL);
|
||||||
|
|
||||||
/* transparent initialization stage */
|
/* transparent initialization stage */
|
||||||
|
|||||||
@@ -163,6 +163,44 @@ const ZSTD_CHUNKSIZE_MAX: usize = u32::MAX as usize - ZSTD_CURRENT_MAX;
|
|||||||
const ZSTD_E_END: c_int = 2;
|
const ZSTD_E_END: c_int = 2;
|
||||||
const ZSTD_E_CONTINUE: c_int = 0;
|
const ZSTD_E_CONTINUE: c_int = 0;
|
||||||
const ZSTD_E_FLUSH: c_int = 1;
|
const ZSTD_E_FLUSH: c_int = 1;
|
||||||
|
|
||||||
|
/// Scalar projection for the public `ZSTD_compressStream2` directive policy.
|
||||||
|
///
|
||||||
|
/// The C fallback retains the private context and streaming implementation;
|
||||||
|
/// Rust owns only the public range decision; C retains error encoding and
|
||||||
|
/// diagnostics.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct ZSTD_rust_compressStream2PolicyState {
|
||||||
|
pub end_op: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(offset_of!(ZSTD_rust_compressStream2PolicyState, end_op) == 0);
|
||||||
|
assert!(size_of::<ZSTD_rust_compressStream2PolicyState>() == size_of::<c_int>());
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn compress_stream2_policy(end_op: c_int) -> c_int {
|
||||||
|
if (ZSTD_E_CONTINUE..=ZSTD_E_END).contains(&end_op) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decide whether the public stream end directive is in range before entering
|
||||||
|
/// C's private fallback state machine.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_compressStream2Policy(
|
||||||
|
state: *const ZSTD_rust_compressStream2PolicyState,
|
||||||
|
) -> c_int {
|
||||||
|
let Some(state) = (unsafe { state.as_ref() }) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
compress_stream2_policy(state.end_op)
|
||||||
|
}
|
||||||
|
|
||||||
const ZSTD_C_WINDOW_LOG: c_int = 101;
|
const ZSTD_C_WINDOW_LOG: c_int = 101;
|
||||||
const ZSTD_C_HASH_LOG: c_int = 102;
|
const ZSTD_C_HASH_LOG: c_int = 102;
|
||||||
const ZSTD_C_CHAIN_LOG: c_int = 103;
|
const ZSTD_C_CHAIN_LOG: c_int = 103;
|
||||||
@@ -14033,6 +14071,25 @@ mod tests {
|
|||||||
assert_eq!(context.calls, 0);
|
assert_eq!(context.calls, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compress_stream2_policy_accepts_all_public_directives() {
|
||||||
|
for end_op in [ZSTD_E_CONTINUE, ZSTD_E_FLUSH, ZSTD_E_END] {
|
||||||
|
let state = ZSTD_rust_compressStream2PolicyState { end_op };
|
||||||
|
let result = unsafe { ZSTD_rust_compressStream2Policy(&state) };
|
||||||
|
assert_eq!(result, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compress_stream2_policy_rejects_out_of_range_directives() {
|
||||||
|
for end_op in [c_int::MIN, -1, ZSTD_E_END + 1, c_int::MAX] {
|
||||||
|
let state = ZSTD_rust_compressStream2PolicyState { end_op };
|
||||||
|
let result = unsafe { ZSTD_rust_compressStream2Policy(&state) };
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
}
|
||||||
|
assert_eq!(unsafe { ZSTD_rust_compressStream2Policy(ptr::null()) }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reduce_table_applies_threshold_and_wrapping_subtraction() {
|
fn reduce_table_applies_threshold_and_wrapping_subtraction() {
|
||||||
let mut table = [0, 1, 2, 3, 4, 5, 6, u32::MAX, 0, 0, 0, 0, 0, 0, 0, 0];
|
let mut table = [0, 1, 2, 3, 4, 5, 6, u32::MAX, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|||||||
Reference in New Issue
Block a user