diff --git a/lib/decompress/zstd_ddict.c b/lib/decompress/zstd_ddict.c index 96cc1f2e9..b94a360eb 100644 --- a/lib/decompress/zstd_ddict.c +++ b/lib/decompress/zstd_ddict.c @@ -2,32 +2,7 @@ * ZSTD_DDict implementation moved to rust/src/zstd_ddict.rs. * * Keep this translation unit in the original source list so the C build keeps - * the same header configuration while the Rust static library provides the - * exported symbols. The metadata below is deliberately compiled with the C - * decoder's exact conditional layout: Rust uses it to fill the opaque DCtx - * fields without duplicating optional C layout choices such as DYNAMIC_BMI2. + * the same source topology while the Rust static library provides the + * exported symbols. DDict parameter copying uses the canonical C-produced + * ZSTD_rustDctxView, so this file no longer publishes private DCtx offsets. */ -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd_decompress_internal.h" -#include "zstd_ddict.h" - -const size_t ZSTD_rust_ddict_llt_ptr_offset = offsetof(struct ZSTD_DCtx_s, LLTptr); -const size_t ZSTD_rust_ddict_mlt_ptr_offset = offsetof(struct ZSTD_DCtx_s, MLTptr); -const size_t ZSTD_rust_ddict_oft_ptr_offset = offsetof(struct ZSTD_DCtx_s, OFTptr); -const size_t ZSTD_rust_ddict_huf_ptr_offset = offsetof(struct ZSTD_DCtx_s, HUFptr); -const size_t ZSTD_rust_ddict_entropy_rep_offset = offsetof(struct ZSTD_DCtx_s, entropy.rep); -const size_t ZSTD_rust_ddict_previous_dst_end_offset = offsetof(struct ZSTD_DCtx_s, previousDstEnd); -const size_t ZSTD_rust_ddict_prefix_start_offset = offsetof(struct ZSTD_DCtx_s, prefixStart); -const size_t ZSTD_rust_ddict_virtual_start_offset = offsetof(struct ZSTD_DCtx_s, virtualStart); -const size_t ZSTD_rust_ddict_dict_end_offset = offsetof(struct ZSTD_DCtx_s, dictEnd); -const size_t ZSTD_rust_ddict_lit_entropy_offset = offsetof(struct ZSTD_DCtx_s, litEntropy); -const size_t ZSTD_rust_ddict_fse_entropy_offset = offsetof(struct ZSTD_DCtx_s, fseEntropy); -const size_t ZSTD_rust_ddict_dict_id_offset = offsetof(struct ZSTD_DCtx_s, dictID); - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -const size_t ZSTD_rust_ddict_fuzz_begin_offset = offsetof(struct ZSTD_DCtx_s, dictContentBeginForFuzzing); -const size_t ZSTD_rust_ddict_fuzz_end_offset = offsetof(struct ZSTD_DCtx_s, dictContentEndForFuzzing); -#else -const size_t ZSTD_rust_ddict_fuzz_begin_offset = (size_t)-1; -const size_t ZSTD_rust_ddict_fuzz_end_offset = (size_t)-1; -#endif diff --git a/rust/src/zstd_ddict.rs b/rust/src/zstd_ddict.rs index 021fa635d..43227130d 100644 --- a/rust/src/zstd_ddict.rs +++ b/rust/src/zstd_ddict.rs @@ -12,7 +12,7 @@ use crate::common::{LL_FSE_LOG, ML_FSE_LOG, OFF_FSE_LOG, ZSTD_FRAMEIDSIZE, ZSTD_ use crate::errors::{ERR_isError, ZstdErrorCode, ERROR}; use crate::mem::MEM_readLE32; use std::ffi::c_void; -use std::mem::size_of; +use std::mem::{offset_of, size_of}; use std::os::raw::{c_int, c_uint}; use std::ptr; @@ -25,6 +25,7 @@ const ZSTD_DLM_BY_COPY: c_int = 0; const ZSTD_DLM_BY_REF: c_int = 1; const ZSTD_DCT_RAW_CONTENT: c_int = 1; const ZSTD_DCT_FULL_DICT: c_int = 2; +#[cfg(test)] const ZSTD_DDICT_NO_FUZZING_OFFSET: usize = usize::MAX; type ZstdAllocFunction = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void; @@ -83,6 +84,7 @@ pub struct ZSTD_DCtx { _private: [u8; 0], } +#[cfg(test)] #[derive(Clone, Copy)] struct ZstdDctxOffsets { llt_ptr: usize, @@ -108,73 +110,30 @@ unsafe extern "C" { dict: *const c_void, dict_size: usize, ) -> usize; - - /* - * These are emitted by zstd_ddict.c with the exact C preprocessor state - * used for struct ZSTD_DCtx_s. Keeping the opaque context as C-provided - * offsets avoids duplicating optional fields such as DYNAMIC_BMI2 in Rust. - */ - static ZSTD_rust_ddict_llt_ptr_offset: usize; - static ZSTD_rust_ddict_mlt_ptr_offset: usize; - static ZSTD_rust_ddict_oft_ptr_offset: usize; - static ZSTD_rust_ddict_huf_ptr_offset: usize; - static ZSTD_rust_ddict_entropy_rep_offset: usize; - static ZSTD_rust_ddict_previous_dst_end_offset: usize; - static ZSTD_rust_ddict_prefix_start_offset: usize; - static ZSTD_rust_ddict_virtual_start_offset: usize; - static ZSTD_rust_ddict_dict_end_offset: usize; - static ZSTD_rust_ddict_lit_entropy_offset: usize; - static ZSTD_rust_ddict_fse_entropy_offset: usize; - static ZSTD_rust_ddict_dict_id_offset: usize; - static ZSTD_rust_ddict_fuzz_begin_offset: usize; - static ZSTD_rust_ddict_fuzz_end_offset: usize; } +#[cfg(test)] #[inline] unsafe fn ddict_dctx_offsets() -> ZstdDctxOffsets { - #[cfg(not(test))] - { - unsafe { - ZstdDctxOffsets { - llt_ptr: ZSTD_rust_ddict_llt_ptr_offset, - mlt_ptr: ZSTD_rust_ddict_mlt_ptr_offset, - oft_ptr: ZSTD_rust_ddict_oft_ptr_offset, - huf_ptr: ZSTD_rust_ddict_huf_ptr_offset, - entropy_rep: ZSTD_rust_ddict_entropy_rep_offset, - previous_dst_end: ZSTD_rust_ddict_previous_dst_end_offset, - prefix_start: ZSTD_rust_ddict_prefix_start_offset, - virtual_start: ZSTD_rust_ddict_virtual_start_offset, - dict_end: ZSTD_rust_ddict_dict_end_offset, - lit_entropy: ZSTD_rust_ddict_lit_entropy_offset, - fse_entropy: ZSTD_rust_ddict_fse_entropy_offset, - dict_id: ZSTD_rust_ddict_dict_id_offset, - fuzz_begin: ZSTD_rust_ddict_fuzz_begin_offset, - fuzz_end: ZSTD_rust_ddict_fuzz_end_offset, - } - } - } - - #[cfg(test)] - { - ZstdDctxOffsets { - llt_ptr: 0, - mlt_ptr: size_of::<*const c_void>(), - oft_ptr: 2 * size_of::<*const c_void>(), - huf_ptr: 3 * size_of::<*const c_void>(), - entropy_rep: 4 * size_of::<*const c_void>(), - previous_dst_end: 4 * size_of::<*const c_void>() + 3 * size_of::(), - prefix_start: 5 * size_of::<*const c_void>() + 3 * size_of::(), - virtual_start: 6 * size_of::<*const c_void>() + 3 * size_of::(), - dict_end: 7 * size_of::<*const c_void>() + 3 * size_of::(), - lit_entropy: 8 * size_of::<*const c_void>() + 3 * size_of::(), - fse_entropy: 8 * size_of::<*const c_void>() + 4 * size_of::(), - dict_id: 8 * size_of::<*const c_void>() + 5 * size_of::(), - fuzz_begin: ZSTD_DDICT_NO_FUZZING_OFFSET, - fuzz_end: ZSTD_DDICT_NO_FUZZING_OFFSET, - } + ZstdDctxOffsets { + llt_ptr: 0, + mlt_ptr: size_of::<*const c_void>(), + oft_ptr: 2 * size_of::<*const c_void>(), + huf_ptr: 3 * size_of::<*const c_void>(), + entropy_rep: 4 * size_of::<*const c_void>(), + previous_dst_end: 4 * size_of::<*const c_void>() + 3 * size_of::(), + prefix_start: 5 * size_of::<*const c_void>() + 3 * size_of::(), + virtual_start: 6 * size_of::<*const c_void>() + 3 * size_of::(), + dict_end: 7 * size_of::<*const c_void>() + 3 * size_of::(), + lit_entropy: 8 * size_of::<*const c_void>() + 3 * size_of::(), + fse_entropy: 8 * size_of::<*const c_void>() + 4 * size_of::(), + dict_id: 8 * size_of::<*const c_void>() + 5 * size_of::(), + fuzz_begin: ZSTD_DDICT_NO_FUZZING_OFFSET, + fuzz_end: ZSTD_DDICT_NO_FUZZING_OFFSET, } } +#[cfg(test)] unsafe fn write_dctx_field(dctx: *mut ZSTD_DCtx, offset: usize, value: T) { unsafe { dctx.cast::() @@ -184,6 +143,7 @@ unsafe fn write_dctx_field(dctx: *mut ZSTD_DCtx, offset: usize, value: T) { } } +#[cfg(test)] unsafe fn copy_fuzzing_bounds_at_offsets( dctx: *mut ZSTD_DCtx, begin: *const c_void, @@ -208,6 +168,7 @@ unsafe fn copy_fuzzing_bounds_at_offsets( } } +#[cfg(test)] unsafe fn copy_fuzzing_bounds(dctx: *mut ZSTD_DCtx, begin: *const c_void, end: *const c_void) { let offsets = unsafe { ddict_dctx_offsets() }; unsafe { @@ -215,6 +176,82 @@ unsafe fn copy_fuzzing_bounds(dctx: *mut ZSTD_DCtx, begin: *const c_void, end: * }; } +#[cfg(not(test))] +unsafe fn write_dctx_view_field(field: *mut c_void, value: T) { + unsafe { field.cast::().write_unaligned(value) }; +} + +#[cfg(not(test))] +unsafe fn copy_fuzzing_bounds_view( + view: &crate::zstd_decompress::ZSTD_rustDctxView, + begin: *const c_void, + end: *const c_void, +) { + if view.fuzz_begin.is_null() { + debug_assert!(view.fuzz_end.is_null()); + return; + } + debug_assert!(!view.fuzz_end.is_null()); + unsafe { + write_dctx_view_field(view.fuzz_begin, begin); + write_dctx_view_field(view.fuzz_end, end); + } +} + +#[cfg(not(test))] +unsafe fn copy_ddict_parameters_at_view( + view: &crate::zstd_decompress::ZSTD_rustDctxView, + ddict: *const ZSTD_DDict, +) { + unsafe { + let dict_content = (*ddict).dict_content; + let dict_end = if dict_content.is_null() { + ptr::null() + } else { + dict_content.cast::().add((*ddict).dict_size).cast() + }; + + write_dctx_view_field(view.dict_id, (*ddict).dict_id); + write_dctx_view_field(view.prefix_start, dict_content); + write_dctx_view_field(view.virtual_start, dict_content); + write_dctx_view_field(view.dict_end, dict_end); + write_dctx_view_field(view.previous_dst_end, dict_end); + copy_fuzzing_bounds_view(view, dict_content, dict_end); + + if (*ddict).entropy_present != 0 { + write_dctx_view_field(view.lit_entropy, 1u32); + write_dctx_view_field(view.fse_entropy, 1u32); + write_dctx_view_field( + view.llt_ptr, + (*ddict).entropy.ll_table.as_ptr().cast::(), + ); + write_dctx_view_field( + view.mlt_ptr, + (*ddict).entropy.ml_table.as_ptr().cast::(), + ); + write_dctx_view_field( + view.oft_ptr, + (*ddict).entropy.of_table.as_ptr().cast::(), + ); + write_dctx_view_field( + view.huf_ptr, + (*ddict).entropy.huf_table.as_ptr().cast::(), + ); + let entropy_rep = view + .entropy + .cast::() + .add(offset_of!(ZSTD_entropyDTables, rep)) + .cast::(); + for (index, value) in (*ddict).entropy.rep.iter().copied().enumerate() { + entropy_rep.add(index).write_unaligned(value); + } + } else { + write_dctx_view_field(view.lit_entropy, 0u32); + write_dctx_view_field(view.fse_entropy, 0u32); + } + } +} + #[inline] unsafe fn load_d_entropy( entropy: *mut ZSTD_entropyDTables, @@ -353,6 +390,7 @@ pub unsafe extern "C" fn ZSTD_copyDDictParameters(dctx: *mut ZSTD_DCtx, ddict: * debug_assert!(!dctx.is_null()); debug_assert!(!ddict.is_null()); + #[cfg(test)] unsafe { let offsets = ddict_dctx_offsets(); let dict_content = (*ddict).dict_content; @@ -400,6 +438,12 @@ pub unsafe extern "C" fn ZSTD_copyDDictParameters(dctx: *mut ZSTD_DCtx, ddict: * write_dctx_field(dctx, offsets.fse_entropy, 0u32); } } + + #[cfg(not(test))] + unsafe { + let view = crate::zstd_decompress::dctx_view_for_ddict(dctx.cast()); + copy_ddict_parameters_at_view(&view, ddict); + } } #[no_mangle] diff --git a/rust/src/zstd_decompress.rs b/rust/src/zstd_decompress.rs index ed39ceac7..4f9f40f71 100644 --- a/rust/src/zstd_decompress.rs +++ b/rust/src/zstd_decompress.rs @@ -228,27 +228,27 @@ pub struct ZSTD_entropyDTables_t { /// decoder-context offset. #[repr(C)] #[derive(Clone, Copy)] -struct ZSTD_rustDctxView { +pub(crate) struct ZSTD_rustDctxView { dctx: *mut c_void, - llt_ptr: *mut c_void, - mlt_ptr: *mut c_void, - oft_ptr: *mut c_void, - huf_ptr: *mut c_void, - entropy: *mut c_void, + pub(crate) llt_ptr: *mut c_void, + pub(crate) mlt_ptr: *mut c_void, + pub(crate) oft_ptr: *mut c_void, + pub(crate) huf_ptr: *mut c_void, + pub(crate) entropy: *mut c_void, workspace: *mut c_void, workspace_size: usize, - previous_dst_end: *mut c_void, - prefix_start: *mut c_void, - virtual_start: *mut c_void, - dict_end: *mut c_void, + pub(crate) previous_dst_end: *mut c_void, + pub(crate) prefix_start: *mut c_void, + pub(crate) virtual_start: *mut c_void, + pub(crate) dict_end: *mut c_void, expected: *mut c_void, f_params: *mut c_void, processed_c_size: *mut c_void, decoded_size: *mut c_void, b_type: *mut c_void, stage: *mut c_void, - lit_entropy: *mut c_void, - fse_entropy: *mut c_void, + pub(crate) lit_entropy: *mut c_void, + pub(crate) fse_entropy: *mut c_void, xxh_state: *mut c_void, header_size: *mut c_void, format: *mut c_void, @@ -262,7 +262,7 @@ struct ZSTD_rustDctxView { is_frame_decompression: *mut c_void, ddict_local: *mut c_void, ddict: *mut c_void, - dict_id: *mut c_void, + pub(crate) dict_id: *mut c_void, ddict_is_cold: *mut c_void, dict_uses: *mut c_void, ddict_set: *mut c_void, @@ -294,8 +294,8 @@ struct ZSTD_rustDctxView { header_buffer: *mut c_void, header_buffer_size: usize, oversized_duration: *mut c_void, - fuzz_begin: *mut c_void, - fuzz_end: *mut c_void, + pub(crate) fuzz_begin: *mut c_void, + pub(crate) fuzz_end: *mut c_void, dctx_size: usize, } @@ -530,6 +530,11 @@ unsafe fn dctx_view(dctx: *mut ZSTD_DCtx) -> ZSTD_rustDctxView { unsafe { view.assume_init() } } +#[cfg(not(test))] +pub(crate) unsafe fn dctx_view_for_ddict(dctx: *mut c_void) -> ZSTD_rustDctxView { + unsafe { dctx_view(dctx.cast()) } +} + unsafe fn dctx_trace_view(dctx: *mut ZSTD_DCtx) -> ZSTD_rustDctxTraceView { let mut view = MaybeUninit::::zeroed(); unsafe { ZSTD_rust_dctx_trace_view(dctx, view.as_mut_ptr()) };