Skip to content

Commit 0ff1664

Browse files
authored
Merge pull request #143 from Watson1978/fix/decompress-truncated-frame-hang
Raise instead of hanging on a truncated frame in Zstd.decompress
2 parents e888a83 + dfd04b6 commit 0ff1664

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

‎ext/zstdruby/zstdruby.c‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static VALUE decode_one_frame(ZSTD_DCtx* dctx, const unsigned char* src, size_t
5151

5252
for (;;) {
5353
ZSTD_outBuffer o = (ZSTD_outBuffer){ buf, cap, 0 };
54+
size_t const in_pos_before = in.pos;
5455
size_t ret = ZSTD_decompressStream(dctx, &o, &in);
5556
if (ZSTD_isError(ret)) {
5657
xfree(buf);
@@ -62,6 +63,13 @@ static VALUE decode_one_frame(ZSTD_DCtx* dctx, const unsigned char* src, size_t
6263
if (ret == 0) {
6364
break;
6465
}
66+
/* A non-zero return is a "need more input" hint, not an error, and libzstd's
67+
own noForwardProgress guard is bypassed by the early return it takes on a
68+
truncated frame header -- so the stall has to be detected here. */
69+
if (o.pos == 0 && in.pos == in_pos_before) {
70+
xfree(buf);
71+
rb_raise(rb_eRuntimeError, "ZSTD_decompressStream failed: truncated or incomplete frame");
72+
}
6573
}
6674
xfree(buf);
6775
if (consumed) {

‎spec/zstd-ruby_spec.rb‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ def to_str
116116
expect { Zstd.decompress(Object.new) }.to raise_error(TypeError)
117117
end
118118

119+
it 'should raise (not hang) on a truncated frame' do
120+
full = Zstd.compress('a' * 2000)
121+
[
122+
"\x28\xB5\x2F\xFD".b, # bare zstd magic, no body
123+
full.byteslice(0, 5),
124+
full.byteslice(0, 6),
125+
full.byteslice(0, full.bytesize / 2),
126+
].each do |truncated|
127+
expect { Zstd.decompress(truncated) }.to raise_error(RuntimeError)
128+
end
129+
end
130+
119131
class DummyForDecompress
120132
def to_str
121133
Zstd.compress('abc')

0 commit comments

Comments
 (0)