authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-09-27 14:06:14-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 14:05:17-04:00
log1e805df81d51a338eefaff0535e5f1cca9e22028
tree5fa960d64889a9b741be90720417c3d5957ff265
parent754ea118bc7192b75c337ae95ad54dbe619dea56

deflate.zig: fix bits_left overflow at EndOfStream and @intCast truncation with empty Huffman table


1 files changed, 26 insertions(+), 6 deletions(-)

lib/std/compress/deflate.zig+26-6
...@@ -58,8 +58,10 @@ const Huffman = struct {...@@ -58,8 +58,10 @@ const Huffman = struct {
58 }58 }
5959
60 // All zero.60 // All zero.
61 if (self.count[0] == code_length.len)61 if (self.count[0] == code_length.len) {
62 self.min_code_len = 0;
62 return;63 return;
64 }
6365
64 var left: isize = 1;66 var left: isize = 1;
65 for (self.count[1..]) |val| {67 for (self.count[1..]) |val| {
...@@ -280,7 +282,7 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -280,7 +282,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
280 return self.bits & mask;282 return self.bits & mask;
281 }283 }
282 fn readBits(self: *Self, bits: usize) !u32 {284 fn readBits(self: *Self, bits: usize) !u32 {
283 const val = self.peekBits(bits);285 const val = try self.peekBits(bits);
284 self.discardBits(bits);286 self.discardBits(bits);
285 return val;287 return val;
286 }288 }
...@@ -487,6 +489,8 @@ pub fn InflateStream(comptime ReaderType: type) type {...@@ -487,6 +489,8 @@ pub fn InflateStream(comptime ReaderType: type) type {
487 // We can't read PREFIX_LUT_BITS as we don't want to read past the489 // We can't read PREFIX_LUT_BITS as we don't want to read past the
488 // deflate stream end, use an incremental approach instead.490 // deflate stream end, use an incremental approach instead.
489 var code_len = h.min_code_len;491 var code_len = h.min_code_len;
492 if (code_len == 0)
493 return error.OutOfCodes;
490 while (true) {494 while (true) {
491 _ = try self.peekBits(code_len);495 _ = try self.peekBits(code_len);
492 // Small optimization win, use as many bits as possible in the496 // Small optimization win, use as many bits as possible in the
...@@ -658,11 +662,27 @@ test "lengths overflow" {...@@ -658,11 +662,27 @@ test "lengths overflow" {
658 // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6662 // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
659 // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11663 // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
660 const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };664 const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
665 try std.testing.expectError(error.InvalidLength, testInflate(stream[0..]));
666}
667
668test "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();676test "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
682fn testInflate(data: []const u8) !void {
663 var window: [0x8000]u8 = undefined;683 var window: [0x8000]u8 = undefined;
684 const reader = std.io.fixedBufferStream(data).reader();
664 var inflate = inflateStream(reader, &window);685 var inflate = inflateStream(reader, &window);
665686 var inflated = try inflate.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
666 var buf: [1]u8 = undefined;687 defer std.testing.allocator.free(inflated);
667 try std.testing.expectError(error.InvalidLength, inflate.read(&buf));
668}688}