Keep weak-symbol discovery and private dctx/ddict extraction in the C adapter, but project the exact trace callback types into Rust and invoke them from the Rust trace lifecycle. Preserve the nullable-hook behavior, trace context width, dictionary-cold timing, record field layout, size conversions, and the no-trace build path. Add focused Rust policy tests for callback, record, and null-projection behavior. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests - ulimit -v 41943040; make -j1 - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040; make -j1 -C tests test
404 lines
14 KiB
C
404 lines
14 KiB
C
/*
|
|
* Decoder orchestration is implemented in rust/src/zstd_decompress.rs.
|
|
*
|
|
* `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 while retaining
|
|
* the private layout and configuration-bound legacy leaves. Weak trace-symbol
|
|
* discovery also stays here; Rust receives only a narrow trace projection.
|
|
*/
|
|
|
|
#define ZSTD_STATIC_LINKING_ONLY
|
|
#include "../common/zstd_deps.h"
|
|
#include "../common/error_private.h"
|
|
#include "../common/mem.h"
|
|
#include "../common/zstd_internal.h"
|
|
#include "zstd_decompress_internal.h"
|
|
#include "zstd_ddict.h"
|
|
|
|
/* Keep the three public build-time tuning knobs in the C configuration domain.
|
|
* Rust receives them through the small scalar-policy leaves below rather than
|
|
* baking a second set of defaults into its source. */
|
|
#ifndef ZSTD_HEAPMODE
|
|
# define ZSTD_HEAPMODE 1
|
|
#endif
|
|
|
|
#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
|
|
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
|
|
#endif
|
|
|
|
#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
|
|
# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
|
|
#endif
|
|
|
|
/* Keep this in lock-step with ZSTD_rustDctxView in zstd_decompress.rs.
|
|
* Every pointer that names a scalar is the address of that scalar; array and
|
|
* embedded-object entries name their first byte. */
|
|
typedef struct {
|
|
void* dctx;
|
|
void* llt_ptr;
|
|
void* mlt_ptr;
|
|
void* oft_ptr;
|
|
void* huf_ptr;
|
|
void* entropy;
|
|
void* workspace;
|
|
size_t workspace_size;
|
|
void* previous_dst_end;
|
|
void* prefix_start;
|
|
void* virtual_start;
|
|
void* dict_end;
|
|
void* expected;
|
|
void* f_params;
|
|
void* processed_c_size;
|
|
void* decoded_size;
|
|
void* b_type;
|
|
void* stage;
|
|
void* lit_entropy;
|
|
void* fse_entropy;
|
|
void* xxh_state;
|
|
void* header_size;
|
|
void* format;
|
|
void* force_ignore_checksum;
|
|
void* validate_checksum;
|
|
void* lit_ptr;
|
|
void* custom_mem;
|
|
void* lit_size;
|
|
void* rle_size;
|
|
void* static_size;
|
|
void* is_frame_decompression;
|
|
void* ddict_local;
|
|
void* ddict;
|
|
void* dict_id;
|
|
void* ddict_is_cold;
|
|
void* dict_uses;
|
|
void* ddict_set;
|
|
void* ref_multiple_ddicts;
|
|
void* disable_huf_asm;
|
|
void* max_block_size_param;
|
|
void* stream_stage;
|
|
void* in_buff;
|
|
void* in_buff_size;
|
|
void* in_pos;
|
|
void* max_window_size;
|
|
void* out_buff;
|
|
void* out_buff_size;
|
|
void* out_start;
|
|
void* out_end;
|
|
void* lh_size;
|
|
void* legacy_context;
|
|
void* previous_legacy_version;
|
|
void* legacy_version;
|
|
void* hostage_byte;
|
|
void* no_forward_progress;
|
|
void* out_buffer_mode;
|
|
void* expected_out_buffer;
|
|
void* lit_buffer;
|
|
void* lit_buffer_end;
|
|
void* lit_buffer_location;
|
|
void* lit_extra_buffer;
|
|
size_t lit_extra_buffer_size;
|
|
void* header_buffer;
|
|
size_t header_buffer_size;
|
|
void* oversized_duration;
|
|
void* fuzz_begin;
|
|
void* fuzz_end;
|
|
size_t dctx_size;
|
|
} ZSTD_rustDctxView;
|
|
|
|
typedef char ZSTD_rust_dctx_view_layout[
|
|
(offsetof(ZSTD_rustDctxView, dctx) == 0
|
|
&& offsetof(ZSTD_rustDctxView, static_size) == 29 * sizeof(void*)
|
|
&& offsetof(ZSTD_rustDctxView, dctx_size) == 67 * sizeof(void*)
|
|
&& sizeof(ZSTD_rustDctxView) == 68 * sizeof(void*)) ? 1 : -1];
|
|
|
|
/* Rust exposes this as u64. Use the trace API's exact unsigned-long-long
|
|
* representation instead of U64, whose typedef may be a different C type on
|
|
* some targets even when it has the same width. */
|
|
typedef unsigned long long ZSTD_rustTraceCtx;
|
|
#if ZSTD_TRACE
|
|
typedef ZSTD_rustTraceCtx (*ZSTD_rustTraceBeginFn)(const ZSTD_DCtx* dctx);
|
|
typedef void (*ZSTD_rustTraceEndFn)(ZSTD_rustTraceCtx traceCtx,
|
|
const ZSTD_Trace* trace);
|
|
#else
|
|
typedef ZSTD_rustTraceCtx (*ZSTD_rustTraceBeginFn)(const void* dctx);
|
|
typedef void (*ZSTD_rustTraceEndFn)(ZSTD_rustTraceCtx traceCtx,
|
|
const void* trace);
|
|
#endif
|
|
|
|
typedef struct {
|
|
ZSTD_rustTraceCtx* trace_ctx;
|
|
ZSTD_rustTraceBeginFn begin;
|
|
ZSTD_rustTraceEndFn end;
|
|
const ZSTD_DCtx* dctx;
|
|
const void* ddict;
|
|
int dictionary_is_cold;
|
|
} ZSTD_rustDctxTraceView;
|
|
|
|
void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out);
|
|
void ZSTD_rust_dctx_trace_view(ZSTD_DCtx* dctx,
|
|
ZSTD_rustDctxTraceView* out);
|
|
size_t ZSTD_rust_dctx_sizeof(void);
|
|
void ZSTD_dctx_init_platform(ZSTD_DCtx* dctx);
|
|
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);
|
|
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,
|
|
void* dst, size_t dstCapacity,
|
|
const void* src, size_t srcSize);
|
|
|
|
typedef struct {
|
|
int heapmode;
|
|
void* workspace;
|
|
size_t workspace_size;
|
|
void* dst;
|
|
size_t dst_capacity;
|
|
const void* src;
|
|
size_t src_size;
|
|
} ZSTD_rustDecompressStackProjection;
|
|
typedef char ZSTD_rust_decompress_stack_projection_layout[
|
|
(offsetof(ZSTD_rustDecompressStackProjection, heapmode) == 0
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, workspace) == sizeof(void*)
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, workspace_size)
|
|
== 2 * sizeof(void*)
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, dst)
|
|
== 3 * sizeof(void*)
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, dst_capacity)
|
|
== 4 * sizeof(void*)
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, src)
|
|
== 5 * sizeof(void*)
|
|
&& offsetof(ZSTD_rustDecompressStackProjection, src_size)
|
|
== 6 * sizeof(void*)
|
|
&& sizeof(ZSTD_rustDecompressStackProjection) == 7 * sizeof(void*))
|
|
? 1 : -1];
|
|
|
|
typedef ZSTD_DCtx* (*ZSTD_rustInitStaticDCtxFn)(void* workspace,
|
|
size_t workspace_size);
|
|
typedef size_t (*ZSTD_rustDecompressStackContextFn)(
|
|
ZSTD_DCtx* dctx, void* dst, size_t dstCapacity,
|
|
const void* src, size_t srcSize);
|
|
typedef struct {
|
|
ZSTD_rustInitStaticDCtxFn init_static_dctx;
|
|
ZSTD_rustDecompressStackContextFn decompress_context;
|
|
} ZSTD_rustDecompressStackCallbacks;
|
|
typedef char ZSTD_rust_decompress_stack_callbacks_layout[
|
|
(offsetof(ZSTD_rustDecompressStackCallbacks, init_static_dctx) == 0
|
|
&& offsetof(ZSTD_rustDecompressStackCallbacks, decompress_context)
|
|
== sizeof(void*)
|
|
&& sizeof(ZSTD_rustDecompressStackCallbacks) == 2 * sizeof(void*))
|
|
? 1 : -1];
|
|
|
|
size_t ZSTD_rust_decompress_stack_action(
|
|
const ZSTD_rustDecompressStackProjection* projection,
|
|
const ZSTD_rustDecompressStackCallbacks* callbacks);
|
|
typedef struct {
|
|
size_t configured_max_window_size;
|
|
} ZSTD_rustDefaultMaxWindowProjection;
|
|
typedef char ZSTD_rust_default_max_window_projection_layout[
|
|
(offsetof(ZSTD_rustDefaultMaxWindowProjection,
|
|
configured_max_window_size) == 0
|
|
&& sizeof(ZSTD_rustDefaultMaxWindowProjection) == sizeof(size_t))
|
|
? 1 : -1];
|
|
size_t ZSTD_rust_default_max_window_policy(
|
|
const ZSTD_rustDefaultMaxWindowProjection* projection);
|
|
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 {
|
|
int configured_mode;
|
|
} ZSTD_rustHeapModeProjection;
|
|
typedef char ZSTD_rust_heapmode_projection_layout[
|
|
(offsetof(ZSTD_rustHeapModeProjection, configured_mode) == 0
|
|
&& sizeof(ZSTD_rustHeapModeProjection) == sizeof(int))
|
|
? 1 : -1];
|
|
int ZSTD_rust_heapmode_policy(const ZSTD_rustHeapModeProjection* projection);
|
|
typedef struct {
|
|
unsigned configured_level;
|
|
} ZSTD_rustLegacySupportProjection;
|
|
typedef char ZSTD_rust_legacy_support_projection_layout[
|
|
(offsetof(ZSTD_rustLegacySupportProjection, configured_level) == 0
|
|
&& sizeof(ZSTD_rustLegacySupportProjection) == sizeof(unsigned))
|
|
? 1 : -1];
|
|
unsigned ZSTD_rust_legacy_support_policy(
|
|
const ZSTD_rustLegacySupportProjection* projection);
|
|
unsigned ZSTD_rust_legacy_support(void);
|
|
|
|
void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out)
|
|
{
|
|
ZSTD_memset(out, 0, sizeof(*out));
|
|
if (dctx == NULL) return;
|
|
|
|
out->dctx = dctx;
|
|
out->llt_ptr = &dctx->LLTptr;
|
|
out->mlt_ptr = &dctx->MLTptr;
|
|
out->oft_ptr = &dctx->OFTptr;
|
|
out->huf_ptr = &dctx->HUFptr;
|
|
out->entropy = &dctx->entropy;
|
|
out->workspace = dctx->workspace;
|
|
out->workspace_size = sizeof(dctx->workspace);
|
|
out->previous_dst_end = &dctx->previousDstEnd;
|
|
out->prefix_start = &dctx->prefixStart;
|
|
out->virtual_start = &dctx->virtualStart;
|
|
out->dict_end = &dctx->dictEnd;
|
|
out->expected = &dctx->expected;
|
|
out->f_params = &dctx->fParams;
|
|
out->processed_c_size = &dctx->processedCSize;
|
|
out->decoded_size = &dctx->decodedSize;
|
|
out->b_type = &dctx->bType;
|
|
out->stage = &dctx->stage;
|
|
out->lit_entropy = &dctx->litEntropy;
|
|
out->fse_entropy = &dctx->fseEntropy;
|
|
out->xxh_state = &dctx->xxhState;
|
|
out->header_size = &dctx->headerSize;
|
|
out->format = &dctx->format;
|
|
out->force_ignore_checksum = &dctx->forceIgnoreChecksum;
|
|
out->validate_checksum = &dctx->validateChecksum;
|
|
out->lit_ptr = &dctx->litPtr;
|
|
out->custom_mem = &dctx->customMem;
|
|
out->lit_size = &dctx->litSize;
|
|
out->rle_size = &dctx->rleSize;
|
|
out->static_size = &dctx->staticSize;
|
|
out->is_frame_decompression = &dctx->isFrameDecompression;
|
|
out->ddict_local = &dctx->ddictLocal;
|
|
out->ddict = &dctx->ddict;
|
|
out->dict_id = &dctx->dictID;
|
|
out->ddict_is_cold = &dctx->ddictIsCold;
|
|
out->dict_uses = &dctx->dictUses;
|
|
out->ddict_set = &dctx->ddictSet;
|
|
out->ref_multiple_ddicts = &dctx->refMultipleDDicts;
|
|
out->disable_huf_asm = &dctx->disableHufAsm;
|
|
out->max_block_size_param = &dctx->maxBlockSizeParam;
|
|
out->stream_stage = &dctx->streamStage;
|
|
out->in_buff = &dctx->inBuff;
|
|
out->in_buff_size = &dctx->inBuffSize;
|
|
out->in_pos = &dctx->inPos;
|
|
out->max_window_size = &dctx->maxWindowSize;
|
|
out->out_buff = &dctx->outBuff;
|
|
out->out_buff_size = &dctx->outBuffSize;
|
|
out->out_start = &dctx->outStart;
|
|
out->out_end = &dctx->outEnd;
|
|
out->lh_size = &dctx->lhSize;
|
|
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
|
out->legacy_context = &dctx->legacyContext;
|
|
out->previous_legacy_version = &dctx->previousLegacyVersion;
|
|
out->legacy_version = &dctx->legacyVersion;
|
|
#endif
|
|
out->hostage_byte = &dctx->hostageByte;
|
|
out->no_forward_progress = &dctx->noForwardProgress;
|
|
out->out_buffer_mode = &dctx->outBufferMode;
|
|
out->expected_out_buffer = &dctx->expectedOutBuffer;
|
|
out->lit_buffer = &dctx->litBuffer;
|
|
out->lit_buffer_end = &dctx->litBufferEnd;
|
|
out->lit_buffer_location = &dctx->litBufferLocation;
|
|
out->lit_extra_buffer = dctx->litExtraBuffer;
|
|
out->lit_extra_buffer_size = sizeof(dctx->litExtraBuffer);
|
|
out->header_buffer = dctx->headerBuffer;
|
|
out->header_buffer_size = sizeof(dctx->headerBuffer);
|
|
out->oversized_duration = &dctx->oversizedDuration;
|
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
|
out->fuzz_begin = &dctx->dictContentBeginForFuzzing;
|
|
out->fuzz_end = &dctx->dictContentEndForFuzzing;
|
|
#endif
|
|
out->dctx_size = sizeof(*dctx);
|
|
}
|
|
|
|
size_t ZSTD_rust_dctx_sizeof(void)
|
|
{
|
|
return sizeof(ZSTD_DCtx);
|
|
}
|
|
|
|
void ZSTD_dctx_init_platform(ZSTD_DCtx* dctx)
|
|
{
|
|
#if DYNAMIC_BMI2
|
|
ZSTD_rust_dctx_init_platform(&dctx->bmi2, DYNAMIC_BMI2);
|
|
#else
|
|
(void)dctx;
|
|
ZSTD_rust_dctx_init_platform(NULL, DYNAMIC_BMI2);
|
|
#endif
|
|
}
|
|
|
|
size_t ZSTD_rust_dctx_default_max_window_size(void)
|
|
{
|
|
ZSTD_rustDefaultMaxWindowProjection const projection = {
|
|
ZSTD_MAXWINDOWSIZE_DEFAULT
|
|
};
|
|
return ZSTD_rust_default_max_window_policy(&projection);
|
|
}
|
|
|
|
int ZSTD_rust_no_forward_progress_max(void)
|
|
{
|
|
ZSTD_rustNoForwardProgressProjection const projection = {
|
|
ZSTD_NO_FORWARD_PROGRESS_MAX
|
|
};
|
|
return ZSTD_rust_no_forward_progress_policy(&projection);
|
|
}
|
|
|
|
int ZSTD_rust_heapmode(void)
|
|
{
|
|
ZSTD_rustHeapModeProjection const projection = {
|
|
ZSTD_HEAPMODE
|
|
};
|
|
return ZSTD_rust_heapmode_policy(&projection);
|
|
}
|
|
|
|
size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity,
|
|
const void* src, size_t srcSize)
|
|
{
|
|
ZSTD_DCtx dctx;
|
|
ZSTD_rustDecompressStackProjection const projection = {
|
|
ZSTD_rust_heapmode(),
|
|
&dctx,
|
|
sizeof(dctx),
|
|
dst,
|
|
dstCapacity,
|
|
src,
|
|
srcSize
|
|
};
|
|
ZSTD_rustDecompressStackCallbacks const callbacks = {
|
|
ZSTD_initStaticDCtx,
|
|
ZSTD_rust_decompress_stack_context
|
|
};
|
|
return ZSTD_rust_decompress_stack_action(&projection, &callbacks);
|
|
}
|
|
|
|
void ZSTD_rust_dctx_trace_view(ZSTD_DCtx* dctx,
|
|
ZSTD_rustDctxTraceView* out)
|
|
{
|
|
ZSTD_memset(out, 0, sizeof(*out));
|
|
out->dctx = dctx;
|
|
#if ZSTD_TRACE
|
|
out->trace_ctx = &dctx->traceCtx;
|
|
out->begin = (ZSTD_trace_decompress_begin != NULL)
|
|
? ZSTD_trace_decompress_begin : NULL;
|
|
out->end = (ZSTD_trace_decompress_end != NULL)
|
|
? ZSTD_trace_decompress_end : NULL;
|
|
out->ddict = dctx->ddict;
|
|
out->dictionary_is_cold = dctx->ddictIsCold;
|
|
#endif
|
|
}
|
|
|
|
/* The Rust dispatcher has all version-specific legacy implementations. Keep
|
|
* the active C configuration as a scalar leaf so test builds, which compile
|
|
* every Rust legacy module but vary this C macro per target, retain the
|
|
* historical support boundary. Rust owns normalization of that scalar. */
|
|
unsigned ZSTD_rust_legacy_support(void)
|
|
{
|
|
ZSTD_rustLegacySupportProjection const projection = {
|
|
#if defined(ZSTD_LEGACY_SUPPORT)
|
|
ZSTD_LEGACY_SUPPORT
|
|
#else
|
|
0
|
|
#endif
|
|
};
|
|
return ZSTD_rust_legacy_support_policy(&projection);
|
|
}
|