authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2025-08-07 23:40:08+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-08-07 14:40:08-07:00
log6de23100352b9c94cc8c92737687091917951df3
treebe8e7a019f147e1e41db5846c7e91380e6d0bd9b
parent8843631f7ecfe0a7756a2f1f0bc99a24b57c2fcc
signaturebadge-check Signed by PGP key B5690EEEBB952194

flate change bit reader Bits to usize (#24719)

Don't see why byte returned from specialPeek needs to be shifted by remaining_needed_bits. I believe that decision in specialPeek should be done on the number of the remaining bits not of the content of that bits. Some test result are changed, but they are now consistent with the original state as found in: https://github.com/ziglang/zig/blame/5f790464b0d5da3c4c1a7252643e7cdd4c4b605e/lib/std/compress/flate/Decompress.zig Changing Bits from usize to u32 or u64 now returns same results. * flate: simplify peekBitsEnding `peekBits` returns at most asked number of bits. Fails with EndOfStream when there are no available bits. If there are less bits available than asked still returns that available bits. Hopefully this change better reflects intention. On first input stream peek error we break the loop.

1 files changed, 12 insertions(+), 23 deletions(-)

lib/std/compress/flate/Decompress.zig+12-23
......@@ -25,8 +25,7 @@ state: State,
2525
2626err: ?Error,
2727
28/// TODO: change this to usize
29const Bits = u64;
28const Bits = usize;
3029
3130const BlockType = enum(u2) {
3231 stored = 0,
......@@ -550,29 +549,19 @@ fn peekBitsEnding(d: *Decompress, comptime U: type) !U {
550549 var u: Bits = 0;
551550 var remaining_needed_bits = @bitSizeOf(U) - remaining_bits;
552551 var i: usize = 0;
553 while (remaining_needed_bits >= 8) {
554 const byte = try specialPeek(in, next_bits, i);
555 u |= @as(Bits, byte) << @intCast(i * 8);
556 remaining_needed_bits -= 8;
552 while (remaining_needed_bits > 0) {
553 const peeked = in.peek(i + 1) catch |err| switch (err) {
554 error.ReadFailed => return error.ReadFailed,
555 error.EndOfStream => break,
556 };
557 u |= @as(Bits, peeked[i]) << @intCast(i * 8);
558 remaining_needed_bits -|= 8;
557559 i += 1;
558560 }
559 if (remaining_needed_bits != 0) {
560 const byte = try specialPeek(in, next_bits, i);
561 u |= @as(Bits, byte) << @intCast((i * 8) + remaining_needed_bits);
562 }
561 if (remaining_bits == 0 and i == 0) return error.EndOfStream;
563562 return @truncate((u << remaining_bits) | next_bits);
564563}
565564
566/// If there is any unconsumed data, handles EndOfStream by pretending there
567/// are zeroes afterwards.
568fn specialPeek(in: *Reader, next_bits: Bits, i: usize) Reader.Error!u8 {
569 const peeked = in.peek(i + 1) catch |err| switch (err) {
570 error.ReadFailed => return error.ReadFailed,
571 error.EndOfStream => if (next_bits == 0 and i == 0) return error.EndOfStream else return 0,
572 };
573 return peeked[i];
574}
575
576565fn tossBits(d: *Decompress, n: u4) !void {
577566 const remaining_bits = d.remaining_bits;
578567 const next_bits = d.next_bits;
......@@ -1032,7 +1021,7 @@ test "failing invalid-tree01" {
10321021 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
10331022}
10341023test "failing invalid-tree02" {
1035 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.EndOfStream);
1024 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree);
10361025}
10371026test "failing invalid-tree03" {
10381027 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
......@@ -1065,7 +1054,7 @@ test "failing puff10" {
10651054 try testFailure(.raw, @embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
10661055}
10671056test "failing puff11" {
1068 try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.EndOfStream);
1057 try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch);
10691058}
10701059test "failing puff12" {
10711060 try testFailure(.raw, @embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
......@@ -1137,7 +1126,7 @@ test "deflate-stream" {
11371126}
11381127
11391128test "empty-distance-alphabet01" {
1140 try testFailure(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), error.EndOfStream);
1129 try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), "");
11411130}
11421131
11431132test "empty-distance-alphabet02" {