| ... | ... | @@ -58,8 +58,10 @@ const Huffman = struct { |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 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 | 63 | return; |
| 64 | } |
| 63 | 65 | |
| 64 | 66 | var left: isize = 1; |
| 65 | 67 | for (self.count[1..]) |val| { |
| ... | ... | @@ -280,7 +282,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 280 | 282 | return self.bits & mask; |
| 281 | 283 | } |
| 282 | 284 | fn readBits(self: *Self, bits: usize) !u32 { |
| 283 | | const val = self.peekBits(bits); |
| 285 | const val = try self.peekBits(bits); |
| 284 | 286 | self.discardBits(bits); |
| 285 | 287 | return val; |
| 286 | 288 | } |
| ... | ... | @@ -487,6 +489,8 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 487 | 489 | // We can't read PREFIX_LUT_BITS as we don't want to read past the |
| 488 | 490 | // deflate stream end, use an incremental approach instead. |
| 489 | 491 | var code_len = h.min_code_len; |
| 492 | if (code_len == 0) |
| 493 | return error.OutOfCodes; |
| 490 | 494 | while (true) { |
| 491 | 495 | _ = try self.peekBits(code_len); |
| 492 | 496 | // Small optimization win, use as many bits as possible in the |
| ... | ... | @@ -658,11 +662,27 @@ test "lengths overflow" { |
| 658 | 662 | // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6 |
| 659 | 663 | // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11 |
| 660 | 664 | 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 | } |
| 661 | 675 | |
| 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 { |
| 663 | 683 | var window: [0x8000]u8 = undefined; |
| 684 | const reader = std.io.fixedBufferStream(data).reader(); |
| 664 | 685 | 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); |
| 668 | 688 | } |