Skip to content

Commit 83b7ff1

Browse files
commit message
{"subject": "Mark zstd load_dict as unsafe and document invariant", "body": "- Add # Safety docs requiring PyRef<ZstdDict> to outlive the context\n- Wrap calls in load_compressor_dict and load_decompressor_dict with SAFETY comments"}
1 parent 48371d3 commit 83b7ff1

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

crates/stdlib/src/zstd.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,13 @@ mod _zstd {
828828
/// Common path for attaching a dictionary to either context type. Returns
829829
/// the digested `CDict`/`DDict` (if the caller used digested mode) plus
830830
/// the `PyRef<ZstdDict>` we hold to keep the bytes alive for `ref_prefix`.
831-
fn load_dict<L: DictLoader<'static>>(
831+
/// # Safety
832+
///
833+
/// The caller must ensure that the returned `PyRef<ZstdDict>` (if any)
834+
/// outlives the context `ctx`. In `ref_prefix` mode, libzstd stores a
835+
/// raw pointer into the dictionary bytes; the `PyRef` keeps those bytes
836+
/// alive for the required lifetime.
837+
unsafe fn load_dict<L: DictLoader<'static>>(
832838
ctx: &mut L,
833839
dict_obj: Option<PyObjectRef>,
834840
vm: &VirtualMachine,
@@ -883,15 +889,19 @@ mod _zstd {
883889
dict_obj: Option<PyObjectRef>,
884890
vm: &VirtualMachine,
885891
) -> DictLoadResult<zstd_safe::CDict<'static>> {
886-
load_dict::<CCtx<'static>>(cctx, dict_obj, vm)
892+
// SAFETY: The returned `PyRef<ZstdDict>` is stored alongside the
893+
// `CCtx` in `CompressorState`, so it outlives the context.
894+
unsafe { load_dict::<CCtx<'static>>(cctx, dict_obj, vm) }
887895
}
888896

889897
fn load_decompressor_dict(
890898
dctx: &mut DCtx<'static>,
891899
dict_obj: Option<PyObjectRef>,
892900
vm: &VirtualMachine,
893901
) -> DictLoadResult<zstd_safe::DDict<'static>> {
894-
load_dict::<DCtx<'static>>(dctx, dict_obj, vm)
902+
// SAFETY: The returned `PyRef<ZstdDict>` is stored alongside the
903+
// `DCtx` in `DecompressorState`, so it outlives the context.
904+
unsafe { load_dict::<DCtx<'static>>(dctx, dict_obj, vm) }
895905
}
896906

897907
/// Drive `compress_stream2` until the input is fully consumed and, for

0 commit comments

Comments
 (0)