diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7749f5328..b33b985c3 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2780,11 +2780,11 @@ typedef void (*ZSTD_rust_loadDictionaryContent_overflowCorrect_f)( * fields needed by that leaf in the ABI projection; the complete * ZSTD_MatchState_t layout remains private to C. */ typedef struct { - U32* hashTable; - const BYTE* base; - U32 nextToUpdate; - U32 hashLog; - U32 minMatch; + U32** hashTable; + const BYTE** base; + const U32* nextToUpdate; + const U32* hashLog; + const U32* minMatch; int fullTableLoad; int forCDict; } ZSTD_rust_loadDictionaryContentFastTableState; @@ -2795,17 +2795,15 @@ typedef char ZSTD_rust_load_dictionary_fast_table_layout[ && offsetof(ZSTD_rust_loadDictionaryContentFastTableState, nextToUpdate) == 2 * sizeof(void*) && offsetof(ZSTD_rust_loadDictionaryContentFastTableState, hashLog) - == 2 * sizeof(void*) + sizeof(U32) + == 3 * sizeof(void*) && offsetof(ZSTD_rust_loadDictionaryContentFastTableState, minMatch) - == 2 * sizeof(void*) + 2 * sizeof(U32) + == 4 * sizeof(void*) && offsetof(ZSTD_rust_loadDictionaryContentFastTableState, fullTableLoad) - == 2 * sizeof(void*) + 3 * sizeof(U32) + == 5 * sizeof(void*) && offsetof(ZSTD_rust_loadDictionaryContentFastTableState, forCDict) - == 2 * sizeof(void*) + 3 * sizeof(U32) + sizeof(int) + == 5 * sizeof(void*) + sizeof(int) && sizeof(ZSTD_rust_loadDictionaryContentFastTableState) - == ((offsetof(ZSTD_rust_loadDictionaryContentFastTableState, forCDict) - + sizeof(int) + sizeof(void*) - 1) - / sizeof(void*) * sizeof(void*))) + == 5 * sizeof(void*) + 2 * sizeof(int)) ? 1 : -1]; typedef void (*ZSTD_rust_loadDictionaryContent_fillTable_f)( void* context, const void* iend, int dtlm, int tfp); @@ -7016,11 +7014,14 @@ static size_t ZSTD_loadDictionaryContent_callback( assert((tfp == ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_full) || (tfp != ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_fast)); - fastTable.hashTable = ms->hashTable; - fastTable.base = ms->window.base; - fastTable.nextToUpdate = ms->nextToUpdate; - fastTable.hashLog = ms->cParams.hashLog; - fastTable.minMatch = ms->cParams.minMatch; + /* These fields are mutated by the window/publish callbacks before the + * Fast branch runs. Keep pointers to the live match-state fields rather + * than a stale snapshot taken before the Rust orchestrator starts. */ + fastTable.hashTable = &ms->hashTable; + fastTable.base = &ms->window.base; + fastTable.nextToUpdate = &ms->nextToUpdate; + fastTable.hashLog = &ms->cParams.hashLog; + fastTable.minMatch = &ms->cParams.minMatch; fastTable.fullTableLoad = dtlm == ZSTD_dtlm_full; fastTable.forCDict = tfp == ZSTD_tfp_forCDict; diff --git a/rust/src/zstd_compress_dictionary.rs b/rust/src/zstd_compress_dictionary.rs index d97a899b2..5e9dd3105 100644 --- a/rust/src/zstd_compress_dictionary.rs +++ b/rust/src/zstd_compress_dictionary.rs @@ -141,17 +141,17 @@ type LoadDictionaryContentOverflowCorrectFn = unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void); /// Direct projection for the Fast dictionary-table leaf. /// -/// C copies `nextToUpdate` rather than exposing a pointer into the private -/// match state. `fullTableLoad` and `forCDict` are normalized from the C enum -/// inputs after their original validity assertion has run. +/// C exposes pointers to the live scalar fields needed by the Fast leaf. +/// `fullTableLoad` and `forCDict` are normalized from the C enum inputs after +/// their original validity assertion has run. #[repr(C)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] struct ZSTD_rust_loadDictionaryContentFastTableState { - hash_table: *mut c_uint, - base: *const u8, - next_to_update: c_uint, - hash_log: c_uint, - min_match: c_uint, + hash_table: *const *mut c_uint, + base: *const *const u8, + next_to_update: *const c_uint, + hash_log: *const c_uint, + min_match: *const c_uint, full_table_load: c_int, for_cdict: c_int, } @@ -229,28 +229,25 @@ const _: () = { ); assert!( offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, hash_log) - == 2 * size_of::() + size_of::() + == 3 * size_of::() ); assert!( offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, min_match) - == 2 * size_of::() + 2 * size_of::() + == 4 * size_of::() ); assert!( offset_of!( ZSTD_rust_loadDictionaryContentFastTableState, full_table_load - ) == 2 * size_of::() + 3 * size_of::() + ) == 5 * size_of::() ); assert!( offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, for_cdict) - == 2 * size_of::() + 3 * size_of::() + size_of::() + == 5 * size_of::() + size_of::() ); assert!( size_of::() - == (offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, for_cdict) - + size_of::()) - .div_ceil(size_of::()) - * size_of::() + == 5 * size_of::() + 2 * size_of::() ); assert!(size_of::() == size_of::()); assert!(size_of::() == size_of::()); @@ -369,6 +366,25 @@ fn dictionary_table_policy( } } +#[inline] +unsafe fn fill_fast_dictionary_table( + fast_table: &ZSTD_rust_loadDictionaryContentFastTableState, + end: *const c_void, +) { + unsafe { + ZSTD_rust_fillHashTable( + *fast_table.hash_table, + *fast_table.base, + *fast_table.next_to_update, + end, + *fast_table.hash_log, + *fast_table.min_match, + fast_table.full_table_load, + fast_table.for_cdict, + ) + } +} + unsafe fn load_dictionary_content( state: &ZSTD_rust_loadDictionaryContentState, src: *const c_void, @@ -446,16 +462,7 @@ unsafe fn load_dictionary_content( ) { DictionaryTablePolicy::Fast => unsafe { let fast_table = &*state.fast_table; - ZSTD_rust_fillHashTable( - fast_table.hash_table, - fast_table.base, - fast_table.next_to_update, - iend.cast(), - fast_table.hash_log, - fast_table.min_match, - fast_table.full_table_load, - fast_table.for_cdict, - ) + fill_fast_dictionary_table(fast_table, iend.cast()) }, DictionaryTablePolicy::DoubleFast => unsafe { (state.fill_double_hash_table)( @@ -6467,31 +6474,26 @@ mod tests { for (index, byte) in input.iter_mut().enumerate() { *byte = (index as u8).wrapping_mul(37).wrapping_add(11); } + let hash_table_ptr = hash_table.as_mut_ptr(); + let base_ptr = input.as_ptr(); + let next_to_update = 17u32; + let min_match = 4u32; let projection = ZSTD_rust_loadDictionaryContentFastTableState { - hash_table: hash_table.as_mut_ptr(), - base: input.as_ptr(), - next_to_update: 17, - hash_log, - min_match: 4, + hash_table: &hash_table_ptr, + base: &base_ptr, + next_to_update: &next_to_update, + hash_log: &hash_log, + min_match: &min_match, full_table_load: 1, for_cdict: 1, }; unsafe { - ZSTD_rust_fillHashTable( - projection.hash_table, - projection.base, - projection.next_to_update, - input.as_ptr().wrapping_add(input.len()).cast(), - projection.hash_log, - projection.min_match, - projection.full_table_load, - projection.for_cdict, - ) - }; + fill_fast_dictionary_table(&projection, input.as_ptr().wrapping_add(input.len()).cast()) + } assert!(hash_table.iter().any(|&entry| entry != 0)); - assert_eq!(projection.next_to_update, 17); + assert_eq!(unsafe { *projection.next_to_update }, 17); assert_eq!(projection.full_table_load, 1); assert_eq!(projection.for_cdict, 1); }