feat(compress): move repcode invalidation to Rust

Keep ZSTD_invalidateRepCodes responsible for extracting the private previous
block state and checking that the match window has no external dictionary.
Delegate only the fixed three-entry repcode reset through a narrow pointer ABI,
with a C assertion preserving the Rust side's ZSTD_REP_NUM assumption.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression zstd_compress::tests::invalidate_rep_codes_clears_all_entries` -- passed
- `make -B -C lib -j2 lib` -- passed
- `make -C tests -j2 fuzzer` and `./tests/fuzzer -s4560 -t47 -i48 -v` -- passed
- Required clippy, nightly fmt, and diff checks -- passed
This commit is contained in:
2026-07-18 09:55:01 +02:00
parent 745858e980
commit 4663a3372e
2 changed files with 22 additions and 2 deletions
+4 -2
View File
@@ -298,6 +298,8 @@ size_t ZSTD_rust_copyBlockSequences(
SeqCollector* seqCollector, const SeqStore_t* seqStore,
const U32 prevRepcodes[ZSTD_REP_NUM]);
void ZSTD_rust_resetCompressedBlockState(ZSTD_compressedBlockState_t* bs);
void ZSTD_rust_invalidateRepCodes(U32 rep[ZSTD_REP_NUM]);
typedef char ZSTD_rust_invalidate_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
void ZSTD_rust_confirmRepcodesAndEntropyTables(
ZSTD_compressedBlockState_t** prevCBlock,
ZSTD_compressedBlockState_t** nextCBlock);
@@ -1798,8 +1800,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
* Note : only works with regular variant;
* do not use with extDict variant ! */
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
int i;
for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
ZSTD_compressedBlockState_t* const prevCBlock = cctx->blockState.prevCBlock;
ZSTD_rust_invalidateRepCodes(prevCBlock->rep);
assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
}
+18
View File
@@ -72,6 +72,7 @@ unsafe extern "C" {
const ZSTD_FAST: c_int = 1;
const ZSTD_DFAST: c_int = 2;
const ZSTD_REP_NUM: usize = 3;
#[cfg(test)]
const ZSTD_BM_BUFFERED: c_int = 0;
const ZSTD_BM_STABLE: c_int = 1;
@@ -365,6 +366,14 @@ pub unsafe extern "C" fn ZSTD_rust_copyCDictTableIntoCCtx(
}
}
/// Clear the previous block's repcodes before the next regular compression.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_invalidateRepCodes(rep: *mut u32) {
debug_assert!(!rep.is_null());
let rep = unsafe { std::slice::from_raw_parts_mut(rep, ZSTD_REP_NUM) };
rep.fill(0);
}
#[inline]
fn zeroed_state() -> ZSTD_compressedBlockState_t {
/* The state contains only integer arrays and enum fields. */
@@ -1118,6 +1127,15 @@ mod tests {
);
}
#[test]
fn invalidate_rep_codes_clears_all_entries() {
let mut rep = [11u32, 22, 33];
unsafe { ZSTD_rust_invalidateRepCodes(rep.as_mut_ptr()) };
assert_eq!(rep, [0; ZSTD_REP_NUM]);
}
#[test]
fn public_one_shot_abi_is_c_compatible() {
let entry: unsafe extern "C" fn(*mut c_void, usize, *const c_void, usize, c_int) -> usize =