Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e5c27f
Add _zstd stdlib module backing compression.zstd
JamesClarke7283 May 23, 2026
1def1b4
Fix iOS build by removing static PyMutex<PyTypeRef>
JamesClarke7283 May 23, 2026
ee26123
Fix clippy errors in zstd module
JamesClarke7283 May 23, 2026
fbce9c9
Retrigger CI
JamesClarke7283 May 23, 2026
63103b6
chore: format zstd module
JamesClarke7283 May 23, 2026
77370cb
Update crates/stdlib/src/zstd.rs
JamesClarke7283 May 24, 2026
ace862f
chore: remove rustdoc comments from zstd module
JamesClarke7283 May 24, 2026
07aa356
commit message
JamesClarke7283 May 25, 2026
f7598d6
commit message
JamesClarke7283 May 25, 2026
9b1e29e
Identify zstd parameter enums by type identity, not name
JamesClarke7283 Jun 3, 2026
e6c5b19
Match CPython error behavior in _zstd ZstdCompressor
JamesClarke7283 Jun 3, 2026
dbe4626
Address review: drop decorative separators and unused zstd crate
JamesClarke7283 Aug 9, 2026
9d497f4
Switch _zstd backend from zstd-safe to pure-Rust libzstd-rs-sys
JamesClarke7283 Aug 9, 2026
8fe59b8
Fix data loss in ZstdDecompressor.decompress(max_length=0)
JamesClarke7283 Aug 9, 2026
3d4825e
Drop duplicate spell-checker line in zstd.rs
JamesClarke7283 Aug 9, 2026
52bea59
Address review on _zstd constants, version attrs and dict markers
JamesClarke7283 Aug 19, 2026
1335148
Replace the _zstd flush-mode constants with a CompressMode enum
JamesClarke7283 Aug 19, 2026
68bed04
Correct the _zstd explanatory comments and raise MemoryError on OOM
JamesClarke7283 Aug 19, 2026
e163561
Fix CPython divergences and a crash in the _zstd module
JamesClarke7283 Aug 19, 2026
041f631
Restore Lib/test/test_zstd.py to its vendored CPython state
JamesClarke7283 Aug 19, 2026
2cc9547
Merge main into zstd
JamesClarke7283 Oct 31, 2026
0880de2
Fix zstd parameter errors and concurrent lock waits
JamesClarke7283 Oct 31, 2026
c588dcb
Adapt zstd bindings to current VM object APIs
JamesClarke7283 Oct 31, 2026
6751a62
Borrow the zstd module after resolving imports
JamesClarke7283 Oct 31, 2026
3541742
Simplify the default pledged zstd size
JamesClarke7283 Oct 31, 2026
5c591e7
Fix zstd CI selection and dictionary sample validation
JamesClarke7283 Oct 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix data loss in ZstdDecompressor.decompress(max_length=0)
The zero-cap probe iteration handed libzstd a 1-byte buffer and the
post-loop truncation discarded whatever it emitted, while the input
counter had already advanced past the bytes that produced it — every
decompress(..., max_length=0) call with pending output silently dropped
one byte. The suite never caught it because max_length=0 was only
exercised against zero-output (skippable) frames.

Match CPython's mechanism instead: probe with a zero-size output
buffer, so libzstd consumes input without emitting and never reports
frame completion with un-emitted content. Add a regression snippet
covering lossless zero-cap probes (content, truncated, and skippable
frames), verified byte-exact against CPython.
  • Loading branch information
JamesClarke7283 committed Aug 19, 2026
commit 8fe59b8e930a524231d3260909469e029866868d
31 changes: 12 additions & 19 deletions crates/stdlib/src/zstd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,17 +1403,18 @@ mod _zstd {
let outcome = loop {
iteration += 1;
// Honor `max_length`: stop growing the output buffer once
// we have produced enough. Special-case the first iteration
// when the cap is zero so a zero-output frame (skippable
// frame, empty content frame) can still complete; we hand
// libzstd a 1-byte scratch and discard the byte if it ends
// up writing one.
// we have produced enough. When the cap is zero, hand
// libzstd a zero-size buffer instead: it then consumes
// input without emitting, so zero-output frames (skippable
// frame, empty content frame) still complete while real
// output stays inside libzstd until a later call has room.
// CPython's decompressor uses the same zero-size mechanism.
let grow = match max_length {
Some(maxl) if output.len() >= maxl && iteration > 1 => {
hit_max = true;
break Ok(());
}
Some(maxl) if output.len() >= maxl => 1,
Some(maxl) if output.len() >= maxl => 0,
Some(maxl) => (maxl - output.len()).min(chunk_size),
None => chunk_size,
};
Expand Down Expand Up @@ -1441,7 +1442,10 @@ mod _zstd {
state.eof = true;
break Ok(());
}
let output_was_full = written == grow;
// Only meaningful with a non-zero buffer: libzstd had more
// to emit but ran out of room. A zero-size call (the
// max_length == 0 probe) is not "full".
let output_was_full = grow > 0 && written == grow;
let input_consumed = input.pos == input.size;

if let Some(maxl) = max_length
Expand All @@ -1462,18 +1466,7 @@ mod _zstd {
outcome.map(|()| (output, hit_max, input.pos))
});

let (mut output, mut hit_max, consumed) =
loop_result.map_err(|c| catch_zstd_error(c, vm))?;

// If `max_length == 0` opened a courtesy iteration that produced more
// bytes than the caller asked for, truncate. Should not happen with
// the scratch slicing above, but keep the safety net.
if let Some(maxl) = max_length
&& output.len() > maxl
{
output.truncate(maxl);
hit_max = true;
}
let (output, hit_max, consumed) = loop_result.map_err(|c| catch_zstd_error(c, vm))?;

let remaining = &work_data[consumed..];

Expand Down
51 changes: 51 additions & 0 deletions extra_tests/snippets/stdlib_zstd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from compression.zstd import ZstdCompressor, ZstdDecompressor

# basic roundtrip
payload = b"hello world" * 100
c = ZstdCompressor()
frame = c.compress(payload) + c.flush()
d = ZstdDecompressor()
out = d.decompress(frame)
assert out == payload
assert d.eof
assert not d.needs_input

# max_length=0 must not drop output bytes: probing with a zero cap has to
# leave every byte available to later drain calls (regression: the probe
# used to emit one byte per call into the void).
d = ZstdDecompressor()
out = d.decompress(frame, 0)
assert out == b""
assert not d.eof
assert not d.needs_input
rest = d.decompress(b"", len(payload))
assert rest == payload
assert d.eof

# two zero-cap probes in a row, then drain; still lossless
d = ZstdDecompressor()
assert d.decompress(frame, 0) == b""
assert d.decompress(b"", 0) == b""
assert d.decompress(b"", len(payload)) == payload
assert d.eof

# zero-cap probe on a truncated frame: no output, not at end
d = ZstdDecompressor()
out = d.decompress(frame[:-5], 0)
assert out == b""
assert not d.eof
assert not d.needs_input

# zero-cap probe on a skippable frame completes it
skippable = b"\x50\x2a\x4d\x18\x04\x00\x00\x00abcd"
d = ZstdDecompressor()
assert d.decompress(skippable, 0) == b""
assert d.eof
assert not d.needs_input
assert d.unused_data == b""

# skippable frame followed by trailing bytes lands in unused_data
d = ZstdDecompressor()
assert d.decompress(skippable + b"trail", 0) == b""
assert d.eof
assert d.unused_data == b"trail"