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