Skip to content

Commit 1e805df

Browse files
mattborkandrewrk
authored andcommitted
deflate.zig: fix bits_left overflow at EndOfStream and @intcast truncation with empty Huffman table
1 parent 754ea11 commit 1e805df

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

lib/std/compress/deflate.zig

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ const Huffman = struct {
5858
}
5959

6060
// All zero.
61-
if (self.count[0] == code_length.len)
61+
if (self.count[0] == code_length.len) {
62+
self.min_code_len = 0;
6263
return;
64+
}
6365

6466
var left: isize = 1;
6567
for (self.count[1..]) |val| {
@@ -280,7 +282,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
280282
return self.bits & mask;
281283
}
282284
fn readBits(self: *Self, bits: usize) !u32 {
283-
const val = self.peekBits(bits);
285+
const val = try self.peekBits(bits);
284286
self.discardBits(bits);
285287
return val;
286288
}
@@ -487,6 +489,8 @@ pub fn InflateStream(comptime ReaderType: type) type {
487489
// We can't read PREFIX_LUT_BITS as we don't want to read past the
488490
// deflate stream end, use an incremental approach instead.
489491
var code_len = h.min_code_len;
492+
if (code_len == 0)
493+
return error.OutOfCodes;
490494
while (true) {
491495
_ = try self.peekBits(code_len);
492496
// Small optimization win, use as many bits as possible in the
@@ -658,11 +662,27 @@ test "lengths overflow" {
658662
// f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
659663
// 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
660664
const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
665+
try std.testing.expectError(error.InvalidLength, testInflate(stream[0..]));
666+
}
667+
668+
test "empty distance alphabet" {
669+
// dynamic block with empty distance alphabet is valid if end of data symbol is used immediately
670+
// f dy hlit hdist hclen 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 (18) x128 (18) x128 (1) ( 0) (256)
671+
// 1 10 00000 00000 1111 000 000 010 010 000 000 000 000 000 000 000 000 000 000 000 000 000 001 000 (11) 1110101 (11) 1110101 (0) (10) (0)
672+
const stream = [_]u8{ 0b00000101, 0b11100000, 0b00000001, 0b00001001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00010000, 0b01011100, 0b10111111, 0b00101110 };
673+
try testInflate(stream[0..]);
674+
}
661675

662-
const reader = std.io.fixedBufferStream(&stream).reader();
676+
test "inflateStream fuzzing" {
677+
// see https://github.com/ziglang/zig/issues/9842
678+
try std.testing.expectError(error.EndOfStream, testInflate("\x950000"));
679+
try std.testing.expectError(error.OutOfCodes, testInflate("\x950\x00\x0000000"));
680+
}
681+
682+
fn testInflate(data: []const u8) !void {
663683
var window: [0x8000]u8 = undefined;
684+
const reader = std.io.fixedBufferStream(data).reader();
664685
var inflate = inflateStream(reader, &window);
665-
666-
var buf: [1]u8 = undefined;
667-
try std.testing.expectError(error.InvalidLength, inflate.read(&buf));
686+
var inflated = try inflate.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
687+
defer std.testing.allocator.free(inflated);
668688
}

0 commit comments

Comments
 (0)