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
This commit is contained in:
2026-07-20 19:05:28 +02:00
parent cea0a54ace
commit ffc52de643
2 changed files with 28 additions and 8 deletions
+4 -8
View File
@@ -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,
+24
View File
@@ -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