diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 1d5788ef3..41c735471 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -117,7 +117,6 @@ ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem); -void ZSTD_rust_dctx_copy_prefix(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx); void ZSTD_rust_dctx_trace_begin(ZSTD_DCtx* dctx); void ZSTD_rust_dctx_trace_end(ZSTD_DCtx* dctx, U64 uncompressedSize, U64 compressedSize, int streaming); @@ -261,12 +260,6 @@ ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize, dictContentType, customMem); } -void ZSTD_rust_dctx_copy_prefix(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) -{ - size_t const toCopy = (size_t)((const char*)(&dstDCtx->inBuff) - (const char*)dstDCtx); - ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); -} - void ZSTD_rust_dctx_trace_begin(ZSTD_DCtx* dctx) { #if ZSTD_TRACE diff --git a/rust/README.md b/rust/README.md index 5bee77cb1..15af12850 100644 --- a/rust/README.md +++ b/rust/README.md @@ -119,8 +119,9 @@ zstd ABI: - `zstd_decompress` owns the public decompression context, one-shot, dictionary, parameter, and streaming state machines. Its C shim retains the configuration-dependent context layout and platform details, plus - legacy and trace leaves; Rust owns decoder storage allocation and custom - memory dispatch. + legacy and trace leaves; Rust owns decoder storage allocation, custom + memory dispatch, and the `ZSTD_copyDCtx` prefix copy up to the projected + `inBuff` field. - Command-line frontend - `zstd_cli` owns the Rust parser, safety policy, and dispatch. It is built by the separate `cli/` static-library package only for program archives, diff --git a/rust/src/zstd_decompress.rs b/rust/src/zstd_decompress.rs index 7419e953f..767fe531e 100644 --- a/rust/src/zstd_decompress.rs +++ b/rust/src/zstd_decompress.rs @@ -326,7 +326,6 @@ unsafe extern "C" { streaming: c_int, ); fn ZSTD_rust_dctx_trace_begin(dctx: *mut ZSTD_DCtx); - fn ZSTD_rust_dctx_copy_prefix(dst: *mut ZSTD_DCtx, src: *const ZSTD_DCtx); #[cfg(all( not(test), any( @@ -367,6 +366,12 @@ unsafe fn dctx_view(dctx: *mut ZSTD_DCtx) -> ZSTD_rustDctxView { unsafe { view.assume_init() } } +#[inline] +unsafe fn copy_dctx_prefix(dst: *mut u8, src: *const u8, in_buff: *const c_void) { + let to_copy = (in_buff as usize).wrapping_sub(dst as usize); + unsafe { ptr::copy_nonoverlapping(src, dst, to_copy) }; +} + #[inline] fn legacy_empty_const_ptr() -> *const c_void { ptr::addr_of!(LEGACY_EMPTY_BYTE).cast() @@ -2574,7 +2579,32 @@ pub unsafe extern "C" fn ZSTD_freeDCtx(dctx: *mut ZSTD_DCtx) -> usize { #[no_mangle] pub unsafe extern "C" fn ZSTD_copyDCtx(dst: *mut ZSTD_DCtx, src: *const ZSTD_DCtx) { - unsafe { ZSTD_rust_dctx_copy_prefix(dst, src) } + if dst.is_null() || src.is_null() { + return; + } + let view = unsafe { dctx_view(dst) }; + unsafe { + copy_dctx_prefix(dst.cast(), src.cast(), view.in_buff); + } +} + +#[cfg(test)] +mod dctx_copy_tests { + use super::*; + + #[test] + fn copy_prefix_stops_before_the_input_buffer_field() { + let source = [1u8, 2, 3, 4, 5]; + let mut destination = [0xAAu8; 8]; + let in_buff = unsafe { destination.as_mut_ptr().add(5).cast::() }; + + unsafe { + copy_dctx_prefix(destination.as_mut_ptr(), source.as_ptr(), in_buff); + } + + assert_eq!(&destination[..5], &source); + assert_eq!(&destination[5..], &[0xAA; 3]); + } } unsafe fn select_frame_ddict(view: &ZSTD_rustDctxView) {