feat(decompress): move decoder allocation bridges into Rust

Decoder orchestration already crossed into Rust, but the C translation unit
still owned the allocation bridge used by every decoder context and dictionary
set. That split kept custom malloc/calloc/free behavior, allocator-pair
validation, and the decoder-context storage lifecycle in C without focused
Rust coverage.

Move those bridges into Rust while keeping the C-defined `ZSTD_DCtx` layout and
configuration-dependent platform, legacy, and trace leaves in C. Rust now
validates custom allocator pairs, allocates and frees the opaque decoder
storage, dispatches default allocations to libc, and preserves calloc's
zero-fill contract for custom allocators. Focused tests cover default memory,
custom callbacks, zeroing, null-safe free, and invalid callback pairs.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --lib -- --test-threads=1` -- 447 passed
- `cargo test --manifest-path rust/Cargo.toml --lib zstd_decompress -- --test-threads=1` -- 6 passed
- `cargo clippy --manifest-path rust/Cargo.toml --lib -- -D warnings` -- passed
- `cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check` -- passed
- `make -B -C lib -j2 lib` -- passed
- `make -B -C tests -j2 test-cli-tests` -- passed
- `ZSTREAM_TESTTIME=-T2s make -B -C tests -j2 test-zstream` -- passed
- `FUZZERTEST=-T5s make -B -C tests -j2 test-fuzzer` -- passed
- `make -B -C tests/fuzz -j2 all` and `sequence_compression_api` -- passed
- `make -C tests -j2 test-zstd` -- passed, including large-data cases
This commit is contained in:
2026-07-18 20:17:16 +02:00
parent 20bbb66676
commit 1422d64300
2 changed files with 156 additions and 40 deletions
+2 -35
View File
@@ -4,14 +4,12 @@
* `ZSTD_DCtx_s` is intentionally still allocated and laid out by C: its
* optional members vary with the build configuration and the block decoder
* shares that object. This translation unit is therefore a deliberately
* narrow ABI adapter. It projects field addresses to Rust, keeps allocation
* ownership in the C allocator domain, and retains the configuration-bound
* legacy and trace leaves.
* narrow ABI adapter. It projects field addresses to Rust while retaining
* the private layout and configuration-bound legacy and trace leaves.
*/
#define ZSTD_STATIC_LINKING_ONLY
#include "../common/zstd_deps.h"
#include "../common/allocations.h"
#include "../common/error_private.h"
#include "../common/mem.h"
#include "../common/zstd_internal.h"
@@ -113,17 +111,12 @@ typedef struct {
void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out);
size_t ZSTD_rust_dctx_sizeof(void);
ZSTD_DCtx* ZSTD_rust_dctx_alloc(ZSTD_customMem customMem);
void ZSTD_rust_dctx_free_storage(ZSTD_DCtx* dctx, ZSTD_customMem customMem);
void ZSTD_rust_dctx_init_platform(ZSTD_DCtx* dctx);
size_t ZSTD_rust_dctx_default_max_window_size(void);
int ZSTD_rust_no_forward_progress_max(void);
int ZSTD_rust_heapmode(void);
size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity,
const void* src, size_t srcSize);
void* ZSTD_rust_custom_malloc(size_t size, ZSTD_customMem customMem);
void* ZSTD_rust_custom_calloc(size_t size, ZSTD_customMem customMem);
void ZSTD_rust_custom_free(void* allocation, ZSTD_customMem customMem);
ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize,
ZSTD_dictLoadMethod_e dictLoadMethod,
ZSTD_dictContentType_e dictContentType,
@@ -229,17 +222,6 @@ size_t ZSTD_rust_dctx_sizeof(void)
return sizeof(ZSTD_DCtx);
}
ZSTD_DCtx* ZSTD_rust_dctx_alloc(ZSTD_customMem customMem)
{
if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
return (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(ZSTD_DCtx), customMem);
}
void ZSTD_rust_dctx_free_storage(ZSTD_DCtx* dctx, ZSTD_customMem customMem)
{
ZSTD_customFree(dctx, customMem);
}
void ZSTD_rust_dctx_init_platform(ZSTD_DCtx* dctx)
{
#if DYNAMIC_BMI2
@@ -285,21 +267,6 @@ size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity,
#endif
}
void* ZSTD_rust_custom_malloc(size_t size, ZSTD_customMem customMem)
{
return ZSTD_customMalloc(size, customMem);
}
void* ZSTD_rust_custom_calloc(size_t size, ZSTD_customMem customMem)
{
return ZSTD_customCalloc(size, customMem);
}
void ZSTD_rust_custom_free(void* allocation, ZSTD_customMem customMem)
{
ZSTD_customFree(allocation, customMem);
}
ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize,
ZSTD_dictLoadMethod_e dictLoadMethod,
ZSTD_dictContentType_e dictContentType,