From 3ec8f03850c29c0eacbffbbaa15459bccf66fadd Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 00:40:55 +0200 Subject: [PATCH] feat(compress): project continue overflow correction into Rust Pass the existing overflow-correction projection directly through the compressContinue ABI so Rust owns the correction decision and ordering while C retains only the table/workspace callbacks. Remove the redundant C forwarding adapter and keep the stack projection valid for synchronous dispatch. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo fmt --all -- --check - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --lib zstd_compress::tests::compress_continue -- --nocapture - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --all-targets -- -D warnings - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test - ulimit -v 41943040; make -j1 - ulimit -v 41943040; make -j1 -C tests test-zstream ZSTREAM_TESTTIME=-T2s - ulimit -v 41943040; make -j1 -C tests test-fuzzer FUZZERTEST=-T3s FUZZER_FLAGS=--no-big-tests --- lib/compress/zstd_compress.c | 35 ++++++++++---------- rust/src/zstd_compress.rs | 64 ++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index dccd51d00..8b982fd3f 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -888,9 +888,6 @@ typedef struct { } ZSTD_rust_compressContinueWindowState; typedef char ZSTD_rust_compress_continue_window_state_layout[ (sizeof(ZSTD_rust_compressContinueWindowState) == 7 * sizeof(void*)) ? 1 : -1]; -typedef void (*ZSTD_rust_compressContinueWindow_f)(void* context, - const void* src, - size_t srcSize); typedef size_t (*ZSTD_rust_compressContinueBlock_f)(void* context, void* dst, size_t dstCapacity, @@ -901,7 +898,7 @@ typedef struct { void* callbackContext; ZSTD_rust_compressContinueWindowState* windowState; ZSTD_rust_compressContinueWindowState* ldmWindowState; - ZSTD_rust_compressContinueWindow_f correctOverflow; + const ZSTD_rust_overflowCorrectState* overflowState; ZSTD_rust_compressContinueBlock_f compressFrameChunk; ZSTD_rust_compressContinueBlock_f compressBlock; ZSTD_compressionStage_e* stage; @@ -927,7 +924,7 @@ typedef char ZSTD_rust_compress_continue_state_layout[ (offsetof(ZSTD_rust_compressContinueState, callbackContext) == 0 && offsetof(ZSTD_rust_compressContinueState, windowState) == sizeof(void*) && offsetof(ZSTD_rust_compressContinueState, ldmWindowState) == 2 * sizeof(void*) - && offsetof(ZSTD_rust_compressContinueState, correctOverflow) == 3 * sizeof(void*) + && offsetof(ZSTD_rust_compressContinueState, overflowState) == 3 * sizeof(void*) && offsetof(ZSTD_rust_compressContinueState, compressFrameChunk) == 4 * sizeof(void*) && offsetof(ZSTD_rust_compressContinueState, compressBlock) == 5 * sizeof(void*) && offsetof(ZSTD_rust_compressContinueState, stage) == 6 * sizeof(void*) @@ -5618,17 +5615,6 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, } -static void ZSTD_rust_compressContinue_correctOverflow( - void* context, const void* src, size_t srcSize) -{ - ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context; - ZSTD_MatchState_t* const ms = &cctx->blockState.matchState; - - ZSTD_overflowCorrectIfNeeded( - ms, &cctx->workspace, &cctx->appliedParams, - src, (const BYTE*)src + srcSize); -} - static size_t ZSTD_rust_compressContinue_frameChunk( void* context, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -5657,6 +5643,8 @@ static size_t ZSTD_compressContinue_dispatch( ZSTD_rust_compressContinueState state; ZSTD_rust_compressContinueWindowState windowState; ZSTD_rust_compressContinueWindowState ldmWindowState; + ZSTD_rust_overflowCorrectContext overflowContext; + ZSTD_rust_overflowCorrectState overflowState; ZSTD_MatchState_t* const ms = &cctx->blockState.matchState; ZSTD_window_t* const window = &ms->window; ZSTD_window_t* const ldmWindow = &cctx->ldmState.window; @@ -5676,10 +5664,23 @@ static size_t ZSTD_compressContinue_dispatch( ldmWindowState.forceNonContiguous = NULL; ldmWindowState.nextToUpdate = NULL; + overflowContext.matchState = ms; + overflowContext.workspace = &cctx->workspace; + overflowContext.params = &cctx->appliedParams; + overflowState.callbackContext = &overflowContext; + overflowState.nextToUpdate = &ms->nextToUpdate; + overflowState.needCorrection = ZSTD_rust_overflowCorrect_need; + overflowState.correctOverflow = ZSTD_rust_overflowCorrect_correct; + overflowState.markTablesDirty = ZSTD_rust_overflowCorrect_markTablesDirty; + overflowState.reduceIndex = ZSTD_rust_overflowCorrect_reduceIndex; + overflowState.markTablesClean = ZSTD_rust_overflowCorrect_markTablesClean; + overflowState.loadedDictEnd = &ms->loadedDictEnd; + overflowState.dictMatchState = &ms->dictMatchState; + state.callbackContext = cctx; state.windowState = &windowState; state.ldmWindowState = &ldmWindowState; - state.correctOverflow = ZSTD_rust_compressContinue_correctOverflow; + state.overflowState = &overflowState; state.compressFrameChunk = ZSTD_rust_compressContinue_frameChunk; state.compressBlock = ZSTD_rust_compressContinue_block; state.stage = &cctx->stage; diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index 6060aba99..6fa2fcac5 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -793,7 +793,6 @@ pub unsafe extern "C" fn ZSTD_rust_compressFrameChunk( } } -type CompressContinueWindowFn = unsafe extern "C" fn(*mut c_void, *const c_void, usize); type CompressContinueBlockFn = unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *const c_void, usize, c_uint) -> usize; @@ -843,14 +842,14 @@ const _: () = { /// Rust owns stage transitions, frame-header sequencing, input progression, /// and dispatch between the already-migrated frame-chunk/block bodies. The /// frame-header parameters are projected as scalars. The opaque callback -/// context remains in C for overflow correction and context-sensitive block -/// operations; window advancement is projected directly into Rust. +/// context remains in C for overflow-correction callbacks and context-sensitive +/// block operations; window advancement is projected directly into Rust. #[repr(C)] pub struct ZSTD_rust_compressContinueState { callback_context: *mut c_void, window_state: *const ZSTD_rust_compressContinueWindowProjection, ldm_window_state: *const ZSTD_rust_compressContinueWindowProjection, - correct_overflow: CompressContinueWindowFn, + overflow_state: *const ZSTD_rust_overflowCorrectState, compress_frame_chunk: CompressContinueBlockFn, compress_block: CompressContinueBlockFn, stage: *mut c_int, @@ -877,9 +876,7 @@ const _: () = { assert!( offset_of!(ZSTD_rust_compressContinueState, ldm_window_state) == 2 * size_of::() ); - assert!( - offset_of!(ZSTD_rust_compressContinueState, correct_overflow) == 3 * size_of::() - ); + assert!(offset_of!(ZSTD_rust_compressContinueState, overflow_state) == 3 * size_of::()); assert!( offset_of!(ZSTD_rust_compressContinueState, compress_frame_chunk) == 4 * size_of::() ); @@ -1076,7 +1073,11 @@ unsafe fn compress_continue_body_with( } } if frame == 0 { - unsafe { (state.correct_overflow)(state.callback_context, src, src_size) }; + if state.overflow_state.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + let src_end = src.cast::().wrapping_add(src_size).cast(); + unsafe { ZSTD_rust_overflowCorrectIfNeeded(state.overflow_state, src, src_end) }; } let compressed_size = if frame != 0 { @@ -11168,8 +11169,11 @@ mod tests { ldm_window: ZSTD_rust_windowUpdateState, force_non_contiguous: c_int, next_to_update: c_uint, + loaded_dict_end: c_uint, + dict_match_state: *const c_void, window_projection: ZSTD_rust_compressContinueWindowProjection, ldm_window_projection: ZSTD_rust_compressContinueWindowProjection, + overflow_state: Option, } unsafe fn compress_continue_test_context( @@ -11178,13 +11182,29 @@ mod tests { unsafe { &mut *context.cast::() } } - unsafe extern "C" fn compress_continue_test_overflow( + unsafe extern "C" fn compress_continue_test_overflow_need( context: *mut c_void, _src: *const c_void, - _src_size: usize, - ) { + _src_end: *const c_void, + ) -> c_int { let context = unsafe { compress_continue_test_context(context) }; context.overflow_calls += 1; + 0 + } + + unsafe extern "C" fn compress_continue_test_overflow_correct( + _context: *mut c_void, + _src: *const c_void, + ) -> c_uint { + 0 + } + + unsafe extern "C" fn compress_continue_test_overflow_callback(_context: *mut c_void) {} + + unsafe extern "C" fn compress_continue_test_overflow_reduce( + _context: *mut c_void, + _correction: c_uint, + ) { } unsafe extern "C" fn compress_continue_test_frame( @@ -11235,6 +11255,8 @@ mod tests { context.ldm_window = context.window; context.force_non_contiguous = 0; context.next_to_update = ZSTD_WINDOW_START_INDEX; + context.loaded_dict_end = 0; + context.dict_match_state = ptr::null(); context.window_projection = ZSTD_rust_compressContinueWindowProjection { next_src: ptr::addr_of_mut!(context.window.nextSrc), base: ptr::addr_of_mut!(context.window.base), @@ -11253,11 +11275,27 @@ mod tests { force_non_contiguous: ptr::null_mut(), next_to_update: ptr::null_mut(), }; + let callback_context = (context as *mut CompressContinueTestContext).cast(); + context.overflow_state = Some(ZSTD_rust_overflowCorrectState { + callback_context, + next_to_update: ptr::addr_of_mut!(context.next_to_update), + need_correction: Some(compress_continue_test_overflow_need), + correct_overflow: Some(compress_continue_test_overflow_correct), + mark_tables_dirty: Some(compress_continue_test_overflow_callback), + reduce_index: Some(compress_continue_test_overflow_reduce), + mark_tables_clean: Some(compress_continue_test_overflow_callback), + loaded_dict_end: ptr::addr_of_mut!(context.loaded_dict_end), + dict_match_state: ptr::addr_of_mut!(context.dict_match_state), + }); + let overflow_state = context + .overflow_state + .as_ref() + .map_or(ptr::null(), |state| state as *const _); ZSTD_rust_compressContinueState { - callback_context: (context as *mut CompressContinueTestContext).cast(), + callback_context, window_state: &context.window_projection, ldm_window_state: &context.ldm_window_projection, - correct_overflow: compress_continue_test_overflow, + overflow_state, compress_frame_chunk: compress_continue_test_frame, compress_block: compress_continue_test_block, stage,