authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-28 18:23:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
log2d8d0dd9b0c4bd8d51be33da540b45fef2b20ec2
treec1cab6fd594f8842437c4ebaff236c000c95d396
parentc684b21b4f8f13b32535d799d2c76cdb2dccc8f0

std.compress.flate.Decompress: unfuck the test suite


1 files changed, 143 insertions(+), 83 deletions(-)

lib/std/compress/flate/Decompress.zig+143-83
......@@ -909,85 +909,153 @@ test "zlib decompress non compressed block (type 0)" {
909909 }, "Hello world\n");
910910}
911911
912test "fuzzing tests" {
913 const cases = [_]struct {
914 input: []const u8,
915 out: []const u8 = "",
916 err: ?anyerror = null,
917 }{
918 .{ .input = "deflate-stream", .out = @embedFile("testdata/fuzz/deflate-stream.expect") }, // 0
919 .{ .input = "empty-distance-alphabet01" },
920 .{ .input = "empty-distance-alphabet02" },
921 .{ .input = "end-of-stream", .err = error.EndOfStream },
922 .{ .input = "invalid-distance", .err = error.InvalidMatch },
923 .{ .input = "invalid-tree01", .err = error.IncompleteHuffmanTree }, // 5
924 .{ .input = "invalid-tree02", .err = error.IncompleteHuffmanTree },
925 .{ .input = "invalid-tree03", .err = error.IncompleteHuffmanTree },
926 .{ .input = "lengths-overflow", .err = error.InvalidDynamicBlockHeader },
927 .{ .input = "out-of-codes", .err = error.InvalidCode },
928 .{ .input = "puff01", .err = error.WrongStoredBlockNlen }, // 10
929 .{ .input = "puff02", .err = error.EndOfStream },
930 .{ .input = "puff03", .out = &[_]u8{0xa} },
931 .{ .input = "puff04", .err = error.InvalidCode },
932 .{ .input = "puff05", .err = error.EndOfStream },
933 .{ .input = "puff06", .err = error.EndOfStream },
934 .{ .input = "puff08", .err = error.InvalidCode },
935 .{ .input = "puff09", .out = "P" },
936 .{ .input = "puff10", .err = error.InvalidCode },
937 .{ .input = "puff11", .err = error.InvalidMatch },
938 .{ .input = "puff12", .err = error.InvalidDynamicBlockHeader }, // 20
939 .{ .input = "puff13", .err = error.IncompleteHuffmanTree },
940 .{ .input = "puff14", .err = error.EndOfStream },
941 .{ .input = "puff15", .err = error.IncompleteHuffmanTree },
942 .{ .input = "puff16", .err = error.InvalidDynamicBlockHeader },
943 .{ .input = "puff17", .err = error.MissingEndOfBlockCode }, // 25
944 .{ .input = "fuzz1", .err = error.InvalidDynamicBlockHeader },
945 .{ .input = "fuzz2", .err = error.InvalidDynamicBlockHeader },
946 .{ .input = "fuzz3", .err = error.InvalidMatch },
947 .{ .input = "fuzz4", .err = error.OversubscribedHuffmanTree },
948 .{ .input = "puff18", .err = error.OversubscribedHuffmanTree }, // 30
949 .{ .input = "puff19", .err = error.OversubscribedHuffmanTree },
950 .{ .input = "puff20", .err = error.OversubscribedHuffmanTree },
951 .{ .input = "puff21", .err = error.OversubscribedHuffmanTree },
952 .{ .input = "puff22", .err = error.OversubscribedHuffmanTree },
953 .{ .input = "puff23", .err = error.OversubscribedHuffmanTree }, // 35
954 .{ .input = "puff24", .err = error.IncompleteHuffmanTree },
955 .{ .input = "puff25", .err = error.OversubscribedHuffmanTree },
956 .{ .input = "puff26", .err = error.InvalidDynamicBlockHeader },
957 .{ .input = "puff27", .err = error.InvalidDynamicBlockHeader },
958 };
959
960 inline for (cases) |c| {
961 var in: Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input"));
962 var aw: Writer.Allocating = .init(testing.allocator);
963 try aw.ensureUnusedCapacity(flate.history_len);
964 defer aw.deinit();
965
966 var decompress: Decompress = .init(&in, .raw, &.{});
967 const r = &decompress.reader;
968 if (c.err) |expected_err| {
969 try testing.expectError(error.ReadFailed, r.streamRemaining(&aw.writer));
970 try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed);
971 } else {
972 _ = try r.streamRemaining(&aw.writer);
973 try testing.expectEqualStrings(c.out, aw.getWritten());
974 }
975 }
912test "failing end-of-stream" {
913 try testFailure(@embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream);
914}
915test "failing invalid-distance" {
916 try testFailure(@embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch);
917}
918test "failing invalid-tree01" {
919 try testFailure(@embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
920}
921test "failing invalid-tree02" {
922 try testFailure(@embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree);
923}
924test "failing invalid-tree03" {
925 try testFailure(@embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
926}
927test "failing lengths-overflow" {
928 try testFailure(@embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader);
929}
930test "failing out-of-codes" {
931 try testFailure(@embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode);
932}
933test "failing puff01" {
934 try testFailure(@embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen);
935}
936test "failing puff02" {
937 try testFailure(@embedFile("testdata/fuzz/puff02.input"), error.EndOfStream);
938}
939test "failing puff04" {
940 try testFailure(@embedFile("testdata/fuzz/puff04.input"), error.InvalidCode);
941}
942test "failing puff05" {
943 try testFailure(@embedFile("testdata/fuzz/puff05.input"), error.EndOfStream);
944}
945test "failing puff06" {
946 try testFailure(@embedFile("testdata/fuzz/puff06.input"), error.EndOfStream);
947}
948test "failing puff08" {
949 try testFailure(@embedFile("testdata/fuzz/puff08.input"), error.InvalidCode);
950}
951test "failing puff10" {
952 try testFailure(@embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
953}
954test "failing puff11" {
955 try testFailure(@embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch);
956}
957test "failing puff12" {
958 try testFailure(@embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
959}
960test "failing puff13" {
961 try testFailure(@embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree);
962}
963test "failing puff14" {
964 try testFailure(@embedFile("testdata/fuzz/puff14.input"), error.EndOfStream);
965}
966test "failing puff15" {
967 try testFailure(@embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree);
968}
969test "failing puff16" {
970 try testFailure(@embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader);
971}
972test "failing puff17" {
973 try testFailure(@embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode);
974}
975test "failing fuzz1" {
976 try testFailure(@embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader);
977}
978test "failing fuzz2" {
979 try testFailure(@embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader);
980}
981test "failing fuzz3" {
982 try testFailure(@embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch);
983}
984test "failing fuzz4" {
985 try testFailure(@embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree);
986}
987test "failing puff18" {
988 try testFailure(@embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree);
989}
990test "failing puff19" {
991 try testFailure(@embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree);
992}
993test "failing puff20" {
994 try testFailure(@embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree);
995}
996test "failing puff21" {
997 try testFailure(@embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree);
998}
999test "failing puff22" {
1000 try testFailure(@embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree);
1001}
1002test "failing puff23" {
1003 try testFailure(@embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree);
1004}
1005test "failing puff24" {
1006 try testFailure(@embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree);
1007}
1008test "failing puff25" {
1009 try testFailure(@embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree);
1010}
1011test "failing puff26" {
1012 try testFailure(@embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader);
1013}
1014test "failing puff27" {
1015 try testFailure(@embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader);
9761016}
9771017
978test "bug 18966" {
979 const input = @embedFile("testdata/fuzz/bug_18966.input");
980 const expect = @embedFile("testdata/fuzz/bug_18966.expect");
981
982 var in: Reader = .fixed(input);
1018fn testFailure(in: []const u8, expected_err: anyerror) !void {
1019 var reader: Reader = .fixed(in);
9831020 var aw: Writer.Allocating = .init(testing.allocator);
9841021 try aw.ensureUnusedCapacity(flate.history_len);
9851022 defer aw.deinit();
9861023
987 var decompress: Decompress = .init(&in, .gzip, &.{});
988 const r = &decompress.reader;
989 _ = try r.streamRemaining(&aw.writer);
990 try testing.expectEqualStrings(expect, aw.getWritten());
1024 var decompress: Decompress = .init(&reader, .raw, &.{});
1025 try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer));
1026 try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed);
1027}
1028
1029test "deflate-stream" {
1030 try testDecompress(
1031 .raw,
1032 @embedFile("testdata/fuzz/deflate-stream.input"),
1033 @embedFile("testdata/fuzz/deflate-stream.expect"),
1034 );
1035}
1036
1037test "empty-distance-alphabet01" {
1038 try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), "");
1039}
1040
1041test "empty-distance-alphabet02" {
1042 try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet02.input"), "");
1043}
1044
1045test "puff03" {
1046 try testDecompress(.raw, @embedFile("testdata/fuzz/puff03.input"), &.{0xa});
1047}
1048
1049test "puff09" {
1050 try testDecompress(.raw, @embedFile("testdata/fuzz/puff09.input"), "P");
1051}
1052
1053test "bug 18966" {
1054 try testDecompress(
1055 .gzip,
1056 @embedFile("testdata/fuzz/bug_18966.input"),
1057 @embedFile("testdata/fuzz/bug_18966.expect"),
1058 );
9911059}
9921060
9931061test "reading into empty buffer" {
......@@ -1130,21 +1198,13 @@ test "zlib should not overshoot" {
11301198 var out: [128]u8 = undefined;
11311199
11321200 {
1133 const n = try decompress.reader.readSliceShort(out[0..]);
1134
1135 // Expected decompressed data
1201 const n = try decompress.reader.readSliceShort(&out);
11361202 try std.testing.expectEqual(46, n);
11371203 try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]);
1138
1139 // Decompressor don't overshoot underlying reader.
1140 // It is leaving it at the end of compressed data chunk.
1141 try std.testing.expectEqual(data.len - 4, reader.seek);
1142 // TODO what was this testing, exactly?
1143 //try std.testing.expectEqual(0, decompress.unreadBytes());
11441204 }
11451205
11461206 // 4 bytes after compressed chunk are available in reader.
1147 const n = try reader.readSliceShort(out[0..]);
1207 const n = try reader.readSliceShort(&out);
11481208 try std.testing.expectEqual(n, 4);
11491209 try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
11501210}