From ffc52de6431514617a39683aa488469eb35cd9e7 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 19:05:28 +0200 Subject: [PATCH] refactor(decompress): move stack heap-mode policy to Rust Move only the heap-mode branch decision for stack decompression into Rust while retaining the C-owned stack context, static initialization, error codes, and decoder projection. The Rust scalar policy preserves the historical heapmode >= 1 rejection boundary. Test Plan: - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings` -- passed - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings` -- passed - `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` -- passed - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 make -j1` -- passed - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 ./tests/rustLibSmoke` -- passed - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 make -j1 -C tests test` -- passed, including large streaming, native, fuzzer, and zstream phases --- lib/decompress/zstd_decompress.c | 12 ++++-------- rust/src/zstd_decompress.rs | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index c8a68052c..2d8246fd9 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -138,6 +138,7 @@ void ZSTD_rust_dctx_init_platform(void* bmi2, int dynamic_bmi2); size_t ZSTD_rust_dctx_default_max_window_size(void); int ZSTD_rust_no_forward_progress_max(void); int ZSTD_rust_heapmode(void); +int ZSTD_rust_decompress_stack_uses_heap(int heapmode); size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity, const void* src, size_t srcSize); size_t ZSTD_rust_decompress_stack_context(ZSTD_DCtx* dctx, @@ -274,19 +275,14 @@ int ZSTD_rust_heapmode(void) size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { -#if ZSTD_HEAPMODE >= 1 - (void)dst; - (void)dstCapacity; - (void)src; - (void)srcSize; - return ERROR(GENERIC); -#else + if (ZSTD_rust_decompress_stack_uses_heap(ZSTD_HEAPMODE)) { + return ERROR(GENERIC); + } ZSTD_DCtx dctx; ZSTD_DCtx* const initialized = ZSTD_initStaticDCtx(&dctx, sizeof(dctx)); if (initialized == NULL) return ERROR(memory_allocation); return ZSTD_rust_decompress_stack_context(initialized, dst, dstCapacity, src, srcSize); -#endif } void ZSTD_rust_dctx_trace_view(ZSTD_DCtx* dctx, diff --git a/rust/src/zstd_decompress.rs b/rust/src/zstd_decompress.rs index 853cd85ec..bc273607b 100644 --- a/rust/src/zstd_decompress.rs +++ b/rust/src/zstd_decompress.rs @@ -2913,6 +2913,16 @@ mod dctx_trace_tests { mod stack_context_tests { use super::*; + #[test] + fn stack_heapmode_policy_rejects_one_and_above_but_keeps_zero_and_negative() { + for heapmode in [c_int::MIN, -1, 0] { + assert_eq!(ZSTD_rust_decompress_stack_uses_heap(heapmode), 0); + } + for heapmode in [1, c_int::MAX] { + assert_eq!(ZSTD_rust_decompress_stack_uses_heap(heapmode), 1); + } + } + #[repr(C)] struct StackDispatchProbe { static_size: usize, @@ -3625,6 +3635,20 @@ unsafe fn decompress_stack_context( unsafe { dispatch(view.dctx.cast(), dst, dst_capacity, src, src_size) } } +#[inline] +fn decompress_stack_uses_heap(heapmode: c_int) -> bool { + heapmode >= 1 +} + +/// Select whether the C stack-decompression path must reject heap mode. +/// +/// The C caller retains the stack context and static initialization; Rust +/// owns only the configuration scalar's branch policy. +#[no_mangle] +pub extern "C" fn ZSTD_rust_decompress_stack_uses_heap(heapmode: c_int) -> c_int { + c_int::from(decompress_stack_uses_heap(heapmode)) +} + /// Rust policy/dispatch for the C-owned stack context used by heapmode=0. /// /// The context remains opaque here; the C projection supplies only the field