From b9f9c163404a869ec41a533a0b175d814747d390 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Tue, 21 Jul 2026 08:38:40 +0200 Subject: [PATCH] refactor(decompress): move no-progress threshold policy to Rust ZSTD_NO_FORWARD_PROGRESS_MAX is a compile-time override that was returned directly by the C adapter. Keep the active build value in C, where configuration belongs, but pass it through an ABI-checked scalar projection to Rust. Rust now owns the policy boundary and preserves the exact configured threshold, while the existing stalled-stream comparison, error mapping, and private DCtx layout remain unchanged. Test Plan: - `git diff --cached --check` -- passed - Cargo, make, builds, native tests, and heavy verification were not run per request. --- lib/decompress/zstd_decompress.c | 14 ++++++++- rust/src/zstd_decompress.rs | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 7d1f335f7..b9602d51e 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -187,6 +187,15 @@ typedef char ZSTD_rust_decompress_stack_callbacks_layout[ size_t ZSTD_rust_decompress_stack_action( const ZSTD_rustDecompressStackProjection* projection, const ZSTD_rustDecompressStackCallbacks* callbacks); +typedef struct { + int configured_max; +} ZSTD_rustNoForwardProgressProjection; +typedef char ZSTD_rust_no_forward_progress_projection_layout[ + (offsetof(ZSTD_rustNoForwardProgressProjection, configured_max) == 0 + && sizeof(ZSTD_rustNoForwardProgressProjection) == sizeof(int)) + ? 1 : -1]; +int ZSTD_rust_no_forward_progress_policy( + const ZSTD_rustNoForwardProgressProjection* projection); typedef struct { unsigned configured_level; } ZSTD_rustLegacySupportProjection; @@ -316,7 +325,10 @@ size_t ZSTD_rust_dctx_default_max_window_size(void) int ZSTD_rust_no_forward_progress_max(void) { - return ZSTD_NO_FORWARD_PROGRESS_MAX; + ZSTD_rustNoForwardProgressProjection const projection = { + ZSTD_NO_FORWARD_PROGRESS_MAX + }; + return ZSTD_rust_no_forward_progress_policy(&projection); } int ZSTD_rust_heapmode(void) diff --git a/rust/src/zstd_decompress.rs b/rust/src/zstd_decompress.rs index 85505cd57..477918d7a 100644 --- a/rust/src/zstd_decompress.rs +++ b/rust/src/zstd_decompress.rs @@ -310,6 +310,17 @@ const _: () = { assert!(size_of::() == size_of::()); }; +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct ZSTD_rustNoForwardProgressProjection { + pub configured_max: c_int, +} + +const _: () = { + assert!(offset_of!(ZSTD_rustNoForwardProgressProjection, configured_max) == 0); + assert!(size_of::() == size_of::()); +}; + const _: () = { assert!(offset_of!(ZSTD_rustDctxView, dctx) == 0); assert!(offset_of!(ZSTD_rustDctxView, static_size) == 29 * size_of::()); @@ -656,6 +667,45 @@ unsafe fn configured_legacy_support() -> u32 { } } +/// Preserve the active C build's no-forward-progress threshold. +/// +/// C supplies the compile-time value because it may be overridden by the +/// build. Rust owns the scalar policy boundary without baking a second +/// default into the decoder. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_no_forward_progress_policy( + projection: *const ZSTD_rustNoForwardProgressProjection, +) -> c_int { + let Some(projection) = (unsafe { projection.as_ref() }) else { + return 0; + }; + projection.configured_max +} + +#[cfg(test)] +mod no_forward_progress_policy_tests { + use super::*; + + #[test] + fn preserves_the_configured_threshold() { + for configured_max in [c_int::MIN, -1, 0, 1, 16, c_int::MAX] { + let projection = ZSTD_rustNoForwardProgressProjection { configured_max }; + assert_eq!( + unsafe { ZSTD_rust_no_forward_progress_policy(&projection) }, + configured_max + ); + } + } + + #[test] + fn rejects_missing_configuration_projection() { + assert_eq!( + unsafe { ZSTD_rust_no_forward_progress_policy(ptr::null()) }, + 0 + ); + } +} + /// Normalize the C build's legacy-support threshold before dispatch. /// /// C supplies the active compile-time value because test builds intentionally