diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1c9d6846f..c2c2acc57 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2094,6 +2094,20 @@ typedef struct { size_t optimalTSize; size_t asanRedzoneSize; } ZSTD_rustCDictSizing; +typedef char zstd_rust_cdict_sizing_layout[ + (offsetof(ZSTD_rustCDictSizing, cdictSize) == 0 + && offsetof(ZSTD_rustCDictSizing, hufWorkspaceSize) + == sizeof(size_t) + && offsetof(ZSTD_rustCDictSizing, hashLog3Max) + == 2 * sizeof(size_t) + && offsetof(ZSTD_rustCDictSizing, matchTSize) + == 3 * sizeof(size_t) + && offsetof(ZSTD_rustCDictSizing, optimalTSize) + == 4 * sizeof(size_t) + && offsetof(ZSTD_rustCDictSizing, asanRedzoneSize) + == 5 * sizeof(size_t) + && sizeof(ZSTD_rustCDictSizing) == 6 * sizeof(size_t)) + ? 1 : -1]; size_t ZSTD_rust_params_estimateCDictSizeFromCParams( size_t dictSize, ZSTD_compressionParameters cParams, int dictLoadMethod, const ZSTD_rustCDictSizing* sizing); @@ -2658,10 +2672,6 @@ typedef char ZSTD_rust_init_cdict_state_layout[ ? 1 : -1]; typedef int (*ZSTD_rust_createCDictAdvancedValidateCustomMem_f)(void* context); -typedef size_t (*ZSTD_rust_createCDictAdvancedWorkspaceSize_f)( - void* context, size_t dictSize, int dictLoadMethod, - const ZSTD_compressionParameters* cParams, - int useRowMatchFinder, int enableDedicatedDictSearch); typedef void* (*ZSTD_rust_createCDictAdvancedAllocate_f)( void* context, size_t workspaceSize); typedef void (*ZSTD_rust_createCDictAdvancedCreateWorkspace_f)( @@ -2689,7 +2699,7 @@ typedef struct { U32 exclusionMask; U32 ldmDefaultWindowLog; ZSTD_rust_createCDictAdvancedValidateCustomMem_f validateCustomMem; - ZSTD_rust_createCDictAdvancedWorkspaceSize_f workspaceSize; + const ZSTD_rustCDictSizing* sizing; ZSTD_rust_createCDictAdvancedAllocate_f allocate; ZSTD_rust_createCDictAdvancedCreateWorkspace_f createWorkspace; ZSTD_rust_createCDictAdvancedReserveObject_f reserveObject; @@ -2719,7 +2729,7 @@ typedef char ZSTD_rust_create_cdict_advanced_state_layout[ == 5 * sizeof(void*) + sizeof(U32) && offsetof(ZSTD_rust_createCDictAdvancedState, validateCustomMem) == 5 * sizeof(void*) + 2 * sizeof(U32) - && offsetof(ZSTD_rust_createCDictAdvancedState, workspaceSize) + && offsetof(ZSTD_rust_createCDictAdvancedState, sizing) == 6 * sizeof(void*) + 2 * sizeof(U32) && offsetof(ZSTD_rust_createCDictAdvancedState, allocate) == 7 * sizeof(void*) + 2 * sizeof(U32) @@ -6880,28 +6890,6 @@ static int ZSTD_rust_createCDictAdvanced_validateCustomMem(void* context) return ((!customMem->customAlloc) ^ (!customMem->customFree)) == 0; } -static size_t ZSTD_rust_createCDictAdvanced_workspaceSize( - void* context, size_t dictSize, int dictLoadMethod, - const ZSTD_compressionParameters* cParams, - int useRowMatchFinder, int enableDedicatedDictSearch) -{ - (void)context; - if (cParams == NULL) return 0; - { ZSTD_rustCDictSizing const sizing = { - sizeof(ZSTD_CDict), - HUF_WORKSPACE_SIZE, - ZSTD_HASHLOG3_MAX, - sizeof(ZSTD_match_t), - sizeof(ZSTD_optimal_t), - ZSTD_RUST_ASAN_REDZONE_SIZE - }; - return ZSTD_rust_params_estimateCDictWorkspaceSize( - dictSize, *cParams, dictLoadMethod, - useRowMatchFinder, enableDedicatedDictSearch, - &sizing); - } -} - static void* ZSTD_rust_createCDictAdvanced_allocate( void* context, size_t workspaceSize) { @@ -7035,6 +7023,14 @@ ZSTD_CDict* ZSTD_createCDict_advanced2( ZSTD_CCtx_params cctxParams; ZSTD_rust_createCDictAdvancedContext context; ZSTD_rust_createCDictAdvancedState state; + ZSTD_rustCDictSizing const sizing = { + sizeof(ZSTD_CDict), + HUF_WORKSPACE_SIZE, + ZSTD_HASHLOG3_MAX, + sizeof(ZSTD_match_t), + sizeof(ZSTD_optimal_t), + ZSTD_RUST_ASAN_REDZONE_SIZE + }; DEBUGLOG(3, "ZSTD_createCDict_advanced2, dictSize=%u, mode=%u", (unsigned)dictSize, (unsigned)dictContentType); if (originalCctxParams == NULL) return NULL; @@ -7049,7 +7045,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced2( state.exclusionMask = ZSTD_getCParamsExclusionMask(); state.ldmDefaultWindowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; state.validateCustomMem = ZSTD_rust_createCDictAdvanced_validateCustomMem; - state.workspaceSize = ZSTD_rust_createCDictAdvanced_workspaceSize; + state.sizing = &sizing; state.allocate = ZSTD_rust_createCDictAdvanced_allocate; state.createWorkspace = ZSTD_rust_createCDictAdvanced_createWorkspace; state.reserveObject = ZSTD_rust_createCDictAdvanced_reserveObject; diff --git a/rust/src/zstd_compress_dictionary.rs b/rust/src/zstd_compress_dictionary.rs index a5af0630c..53253ea5a 100644 --- a/rust/src/zstd_compress_dictionary.rs +++ b/rust/src/zstd_compress_dictionary.rs @@ -16,11 +16,12 @@ use crate::fse_compress::FSE_buildCTable_wksp; use crate::huf_compress::HUF_readCTable; use crate::zstd_compress::{ZSTD_rust_copyCDictTableIntoCCtx, ZSTD_rust_windowClear}; use crate::zstd_compress_params::{ - ZSTD_compressionParameters, ZSTD_frameParameters, ZSTD_parameters, + ZSTD_compressionParameters, ZSTD_frameParameters, ZSTD_parameters, ZSTD_rustCDictSizing, ZSTD_rust_params_allocateChainTable, ZSTD_rust_params_defaultCLevel, - ZSTD_rust_params_getCParams, ZSTD_rust_params_getParamsInternal, - ZSTD_rust_params_rowMatchFinderUsed, ZSTD_rust_params_shouldAttachDict, - ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_RUST_CPM_CREATE_CDICT, ZSTD_RUST_CPM_NO_ATTACH_DICT, + ZSTD_rust_params_estimateCDictWorkspaceSize, ZSTD_rust_params_getCParams, + ZSTD_rust_params_getParamsInternal, ZSTD_rust_params_rowMatchFinderUsed, + ZSTD_rust_params_shouldAttachDict, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_RUST_CPM_CREATE_CDICT, + ZSTD_RUST_CPM_NO_ATTACH_DICT, }; use crate::zstd_compress_params_api::ZSTD_CCtx_params; use crate::zstd_compress_stats::{ @@ -825,14 +826,6 @@ pub unsafe extern "C" fn ZSTD_rust_createCDict( } type CreateCDictAdvancedValidateCustomMemFn = unsafe extern "C" fn(*mut c_void) -> c_int; -type CreateCDictAdvancedWorkspaceSizeFn = unsafe extern "C" fn( - *mut c_void, - usize, - c_int, - *const ZSTD_compressionParameters, - c_int, - c_int, -) -> usize; type CreateCDictAdvancedAllocateFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void; type CreateCDictAdvancedCreateWorkspaceFn = unsafe extern "C" fn(*mut c_void, *mut c_void, usize); type CreateCDictAdvancedReserveObjectFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void; @@ -852,12 +845,12 @@ type CreateCDictAdvancedFreeWorkspaceFn = unsafe extern "C" fn(*mut c_void, *mut /// Explicit projection for the public `ZSTD_createCDict_advanced2` wrapper. /// -/// Rust owns context-free parameter preparation, custom-memory validation, -/// allocation, and callback ordering. C retains private workspace -/// construction, CDict initialization, and teardown behind narrow callbacks. -/// The three field pointers keep the private `ZSTD_CCtx_params` layout opaque -/// here while allowing C to publish the fields selected by the Rust parameter -/// leaf. +/// Rust owns context-free parameter preparation, workspace-size policy, +/// custom-memory validation, allocation, and callback ordering. C supplies +/// the private layout-size inputs and retains workspace construction, CDict +/// initialization, and teardown behind narrow callbacks. +/// The pointer fields keep the private `ZSTD_CCtx_params` layout opaque here +/// while allowing C to publish the fields selected by the Rust parameter leaf. #[repr(C)] pub struct ZSTD_rust_createCDictAdvancedState { callback_context: *mut c_void, @@ -868,7 +861,7 @@ pub struct ZSTD_rust_createCDictAdvancedState { exclusion_mask: u32, ldm_default_window_log: u32, validate_custom_mem: CreateCDictAdvancedValidateCustomMemFn, - workspace_size: CreateCDictAdvancedWorkspaceSizeFn, + sizing: *const ZSTD_rustCDictSizing, allocate: CreateCDictAdvancedAllocateFn, create_workspace: CreateCDictAdvancedCreateWorkspaceFn, reserve_object: CreateCDictAdvancedReserveObjectFn, @@ -879,6 +872,16 @@ pub struct ZSTD_rust_createCDictAdvancedState { free: CreateCDictAdvancedFreeFn, } +const _: () = { + assert!(offset_of!(ZSTD_rustCDictSizing, cdictSize) == 0); + assert!(offset_of!(ZSTD_rustCDictSizing, hufWorkspaceSize) == size_of::()); + assert!(offset_of!(ZSTD_rustCDictSizing, hashLog3Max) == 2 * size_of::()); + assert!(offset_of!(ZSTD_rustCDictSizing, matchTSize) == 3 * size_of::()); + assert!(offset_of!(ZSTD_rustCDictSizing, optimalTSize) == 4 * size_of::()); + assert!(offset_of!(ZSTD_rustCDictSizing, asanRedzoneSize) == 5 * size_of::()); + assert!(size_of::() == 6 * size_of::()); +}; + const _: () = { assert!(offset_of!(ZSTD_rust_createCDictAdvancedState, callback_context) == 0); assert!(offset_of!(ZSTD_rust_createCDictAdvancedState, cctx_params) == size_of::()); @@ -905,7 +908,7 @@ const _: () = { == size_of::<[usize; 5]>() + size_of::<[u32; 2]>() ); assert!( - offset_of!(ZSTD_rust_createCDictAdvancedState, workspace_size) + offset_of!(ZSTD_rust_createCDictAdvancedState, sizing) == size_of::<[usize; 6]>() + size_of::<[u32; 2]>() ); assert!( @@ -965,6 +968,7 @@ pub unsafe extern "C" fn ZSTD_rust_createCDictAdvanced( || state.cparams.is_null() || state.enable_dedicated_dict_search.is_null() || state.use_row_match_finder.is_null() + || state.sizing.is_null() { return ptr::null_mut(); } @@ -986,13 +990,13 @@ pub unsafe extern "C" fn ZSTD_rust_createCDictAdvanced( } let workspace_size = unsafe { - (state.workspace_size)( - state.callback_context, + ZSTD_rust_params_estimateCDictWorkspaceSize( dict_size, + *state.cparams, dict_load_method, - state.cparams, *state.use_row_match_finder, *state.enable_dedicated_dict_search, + state.sizing, ) }; let workspace = unsafe { (state.allocate)(state.callback_context, workspace_size) }; @@ -4610,12 +4614,6 @@ mod tests { struct CreateCDictAdvancedProbe { events: Vec<&'static str>, custom_mem_valid: c_int, - workspace_size_result: usize, - workspace_size_dict_size: usize, - workspace_size_dict_load_method: c_int, - workspace_size_cparams: *const ZSTD_compressionParameters, - workspace_size_use_row_match_finder: c_int, - workspace_size_enable_dedicated_dict_search: c_int, allocated_workspace: *mut c_void, allocated_workspace_size: usize, created_workspace: *mut c_void, @@ -4644,24 +4642,6 @@ mod tests { probe.custom_mem_valid } - unsafe extern "C" fn create_cdict_advanced_test_workspace_size( - context: *mut c_void, - dict_size: usize, - dict_load_method: c_int, - cparams: *const ZSTD_compressionParameters, - use_row_match_finder: c_int, - enable_dedicated_dict_search: c_int, - ) -> usize { - let probe = unsafe { &mut *context.cast::() }; - probe.events.push("workspace_size"); - probe.workspace_size_dict_size = dict_size; - probe.workspace_size_dict_load_method = dict_load_method; - probe.workspace_size_cparams = cparams; - probe.workspace_size_use_row_match_finder = use_row_match_finder; - probe.workspace_size_enable_dedicated_dict_search = enable_dedicated_dict_search; - probe.workspace_size_result - } - unsafe extern "C" fn create_cdict_advanced_test_allocate( context: *mut c_void, workspace_size: usize, @@ -4761,6 +4741,50 @@ mod tests { storage } + fn create_cdict_advanced_test_cparams() -> ZSTD_compressionParameters { + ZSTD_compressionParameters { + windowLog: 20, + chainLog: 19, + hashLog: 18, + searchLog: 5, + minMatch: 4, + targetLength: 16, + strategy: 3, + } + } + + static CREATE_CDICT_ADVANCED_TEST_SIZING: ZSTD_rustCDictSizing = ZSTD_rustCDictSizing { + cdictSize: 64, + hufWorkspaceSize: 32, + hashLog3Max: 17, + matchTSize: 16, + optimalTSize: 32, + asanRedzoneSize: 0, + }; + + fn create_cdict_advanced_test_sizing() -> *const ZSTD_rustCDictSizing { + &CREATE_CDICT_ADVANCED_TEST_SIZING + } + + fn create_cdict_advanced_expected_workspace_size( + dict_size: usize, + cparams: ZSTD_compressionParameters, + dict_load_method: c_int, + use_row_match_finder: c_int, + enable_dedicated_dict_search: c_int, + ) -> usize { + unsafe { + ZSTD_rust_params_estimateCDictWorkspaceSize( + dict_size, + cparams, + dict_load_method, + use_row_match_finder, + enable_dedicated_dict_search, + create_cdict_advanced_test_sizing(), + ) + } + } + fn create_cdict_advanced_test_state( probe: &mut CreateCDictAdvancedProbe, cctx_params: *mut ZSTD_CCtx_params, @@ -4777,7 +4801,7 @@ mod tests { exclusion_mask: 0, ldm_default_window_log: 27, validate_custom_mem: create_cdict_advanced_test_validate_custom_mem, - workspace_size: create_cdict_advanced_test_workspace_size, + sizing: create_cdict_advanced_test_sizing(), allocate: create_cdict_advanced_test_allocate, create_workspace: create_cdict_advanced_test_create_workspace, reserve_object: create_cdict_advanced_test_reserve_object, @@ -4793,7 +4817,6 @@ mod tests { fn create_cdict_advanced_publishes_params_and_preserves_create_init_order() { let mut probe = CreateCDictAdvancedProbe { custom_mem_valid: 1, - workspace_size_result: 123, allocated_workspace: ptr::dangling_mut(), cdict_result: ptr::dangling_mut(), ..Default::default() @@ -4829,13 +4852,19 @@ mod tests { ZSTD_DCT_RAW_CONTENT, ) }; + let expected_workspace_size = create_cdict_advanced_expected_workspace_size( + dict.len(), + cparams, + ZSTD_DLM_BY_REF, + use_row_match_finder, + enable_dedicated_dict_search, + ); assert_eq!(result, probe.cdict_result); assert_eq!( probe.events, [ "validate", - "workspace_size", "allocate", "create_workspace", "reserve_object", @@ -4844,20 +4873,9 @@ mod tests { "init" ] ); - assert_eq!(probe.workspace_size_dict_size, dict.len()); - assert_eq!(probe.workspace_size_dict_load_method, ZSTD_DLM_BY_REF); - assert_eq!(probe.workspace_size_cparams, &cparams); - assert_eq!( - probe.workspace_size_use_row_match_finder, - use_row_match_finder - ); - assert_eq!( - probe.workspace_size_enable_dedicated_dict_search, - enable_dedicated_dict_search - ); - assert_eq!(probe.allocated_workspace_size, 123); + assert_eq!(probe.allocated_workspace_size, expected_workspace_size); assert_eq!(probe.created_workspace, probe.allocated_workspace); - assert_eq!(probe.created_workspace_size, 123); + assert_eq!(probe.created_workspace_size, expected_workspace_size); assert_eq!(probe.reserved_cdict, probe.cdict_result); assert_eq!(probe.moved_cdict, probe.cdict_result); assert_eq!(probe.initialized_cdict, probe.cdict_result); @@ -4903,12 +4921,11 @@ mod tests { fn create_cdict_advanced_stops_after_allocation_failure() { let mut probe = CreateCDictAdvancedProbe { custom_mem_valid: 1, - workspace_size_result: 321, ..Default::default() }; let mut params_storage = create_cdict_advanced_test_params(); let cctx_params = params_storage.as_mut_ptr(); - let cparams = ZSTD_compressionParameters::default(); + let cparams = create_cdict_advanced_test_cparams(); let enable_dedicated_dict_search = 0; let use_row_match_finder = 0; let state = create_cdict_advanced_test_state( @@ -4924,8 +4941,17 @@ mod tests { }; assert!(result.is_null()); - assert_eq!(probe.events, ["validate", "workspace_size", "allocate"]); - assert_eq!(probe.allocated_workspace_size, 321); + assert_eq!(probe.events, ["validate", "allocate"]); + assert_eq!( + probe.allocated_workspace_size, + create_cdict_advanced_expected_workspace_size( + 0, + cparams, + ZSTD_DLM_BY_REF, + use_row_match_finder, + enable_dedicated_dict_search, + ) + ); assert!(probe.created_workspace.is_null()); assert!(probe.free_workspace.is_null()); assert!(probe.free_cdict.is_null()); @@ -4936,15 +4962,21 @@ mod tests { let workspace = ptr::dangling_mut::(); let mut probe = CreateCDictAdvancedProbe { custom_mem_valid: 1, - workspace_size_result: 321, allocated_workspace: workspace, ..Default::default() }; let mut params_storage = create_cdict_advanced_test_params(); let cctx_params = params_storage.as_mut_ptr(); - let cparams = ZSTD_compressionParameters::default(); + let cparams = create_cdict_advanced_test_cparams(); let enable_dedicated_dict_search = 0; let use_row_match_finder = 0; + let expected_workspace_size = create_cdict_advanced_expected_workspace_size( + 0, + cparams, + ZSTD_DLM_BY_REF, + use_row_match_finder, + enable_dedicated_dict_search, + ); let state = create_cdict_advanced_test_state( &mut probe, cctx_params, @@ -4962,7 +4994,6 @@ mod tests { probe.events, [ "validate", - "workspace_size", "allocate", "create_workspace", "reserve_object", @@ -4970,7 +5001,7 @@ mod tests { ] ); assert_eq!(probe.created_workspace, workspace); - assert_eq!(probe.created_workspace_size, 321); + assert_eq!(probe.created_workspace_size, expected_workspace_size); assert_eq!(probe.free_workspace, workspace); assert!(probe.free_cdict.is_null()); } @@ -4981,7 +5012,6 @@ mod tests { let workspace = ptr::dangling_mut::(); let mut probe = CreateCDictAdvancedProbe { custom_mem_valid: 1, - workspace_size_result: 321, allocated_workspace: workspace, cdict_result: cdict, init_result: ERROR(ZstdErrorCode::MemoryAllocation), @@ -4989,9 +5019,16 @@ mod tests { }; let mut params_storage = create_cdict_advanced_test_params(); let cctx_params = params_storage.as_mut_ptr(); - let cparams = ZSTD_compressionParameters::default(); + let cparams = create_cdict_advanced_test_cparams(); let enable_dedicated_dict_search = 0; let use_row_match_finder = 0; + let expected_workspace_size = create_cdict_advanced_expected_workspace_size( + 0, + cparams, + ZSTD_DLM_BY_REF, + use_row_match_finder, + enable_dedicated_dict_search, + ); let state = create_cdict_advanced_test_state( &mut probe, cctx_params, @@ -5009,7 +5046,6 @@ mod tests { probe.events, [ "validate", - "workspace_size", "allocate", "create_workspace", "reserve_object", @@ -5020,7 +5056,7 @@ mod tests { ] ); assert_eq!(probe.created_workspace, workspace); - assert_eq!(probe.created_workspace_size, 321); + assert_eq!(probe.created_workspace_size, expected_workspace_size); assert_eq!(probe.reserved_cdict, cdict); assert_eq!(probe.moved_cdict, cdict); assert_eq!(probe.initialized_cdict, cdict);