| ... | @@ -909,85 +909,153 @@ test "zlib decompress non compressed block (type 0)" { | ... | @@ -909,85 +909,153 @@ test "zlib decompress non compressed block (type 0)" { |
| 909 | }, "Hello world\n"); | 909 | }, "Hello world\n"); |
| 910 | } | 910 | } |
| 911 | | 911 | |
| 912 | test "fuzzing tests" { | 912 | test "failing end-of-stream" { |
| 913 | const cases = [_]struct { | 913 | try testFailure(@embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream); |
| 914 | input: []const u8, | 914 | } |
| 915 | out: []const u8 = "", | 915 | test "failing invalid-distance" { |
| 916 | err: ?anyerror = null, | 916 | try testFailure(@embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch); |
| 917 | }{ | 917 | } |
| 918 | .{ .input = "deflate-stream", .out = @embedFile("testdata/fuzz/deflate-stream.expect") }, // 0 | 918 | test "failing invalid-tree01" { |
| 919 | .{ .input = "empty-distance-alphabet01" }, | 919 | try testFailure(@embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree); |
| 920 | .{ .input = "empty-distance-alphabet02" }, | 920 | } |
| 921 | .{ .input = "end-of-stream", .err = error.EndOfStream }, | 921 | test "failing invalid-tree02" { |
| 922 | .{ .input = "invalid-distance", .err = error.InvalidMatch }, | 922 | try testFailure(@embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree); |
| 923 | .{ .input = "invalid-tree01", .err = error.IncompleteHuffmanTree }, // 5 | 923 | } |
| 924 | .{ .input = "invalid-tree02", .err = error.IncompleteHuffmanTree }, | 924 | test "failing invalid-tree03" { |
| 925 | .{ .input = "invalid-tree03", .err = error.IncompleteHuffmanTree }, | 925 | try testFailure(@embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree); |
| 926 | .{ .input = "lengths-overflow", .err = error.InvalidDynamicBlockHeader }, | 926 | } |
| 927 | .{ .input = "out-of-codes", .err = error.InvalidCode }, | 927 | test "failing lengths-overflow" { |
| 928 | .{ .input = "puff01", .err = error.WrongStoredBlockNlen }, // 10 | 928 | try testFailure(@embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader); |
| 929 | .{ .input = "puff02", .err = error.EndOfStream }, | 929 | } |
| 930 | .{ .input = "puff03", .out = &[_]u8{0xa} }, | 930 | test "failing out-of-codes" { |
| 931 | .{ .input = "puff04", .err = error.InvalidCode }, | 931 | try testFailure(@embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode); |
| 932 | .{ .input = "puff05", .err = error.EndOfStream }, | 932 | } |
| 933 | .{ .input = "puff06", .err = error.EndOfStream }, | 933 | test "failing puff01" { |
| 934 | .{ .input = "puff08", .err = error.InvalidCode }, | 934 | try testFailure(@embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen); |
| 935 | .{ .input = "puff09", .out = "P" }, | 935 | } |
| 936 | .{ .input = "puff10", .err = error.InvalidCode }, | 936 | test "failing puff02" { |
| 937 | .{ .input = "puff11", .err = error.InvalidMatch }, | 937 | try testFailure(@embedFile("testdata/fuzz/puff02.input"), error.EndOfStream); |
| 938 | .{ .input = "puff12", .err = error.InvalidDynamicBlockHeader }, // 20 | 938 | } |
| 939 | .{ .input = "puff13", .err = error.IncompleteHuffmanTree }, | 939 | test "failing puff04" { |
| 940 | .{ .input = "puff14", .err = error.EndOfStream }, | 940 | try testFailure(@embedFile("testdata/fuzz/puff04.input"), error.InvalidCode); |
| 941 | .{ .input = "puff15", .err = error.IncompleteHuffmanTree }, | 941 | } |
| 942 | .{ .input = "puff16", .err = error.InvalidDynamicBlockHeader }, | 942 | test "failing puff05" { |
| 943 | .{ .input = "puff17", .err = error.MissingEndOfBlockCode }, // 25 | 943 | try testFailure(@embedFile("testdata/fuzz/puff05.input"), error.EndOfStream); |
| 944 | .{ .input = "fuzz1", .err = error.InvalidDynamicBlockHeader }, | 944 | } |
| 945 | .{ .input = "fuzz2", .err = error.InvalidDynamicBlockHeader }, | 945 | test "failing puff06" { |
| 946 | .{ .input = "fuzz3", .err = error.InvalidMatch }, | 946 | try testFailure(@embedFile("testdata/fuzz/puff06.input"), error.EndOfStream); |
| 947 | .{ .input = "fuzz4", .err = error.OversubscribedHuffmanTree }, | 947 | } |
| 948 | .{ .input = "puff18", .err = error.OversubscribedHuffmanTree }, // 30 | 948 | test "failing puff08" { |
| 949 | .{ .input = "puff19", .err = error.OversubscribedHuffmanTree }, | 949 | try testFailure(@embedFile("testdata/fuzz/puff08.input"), error.InvalidCode); |
| 950 | .{ .input = "puff20", .err = error.OversubscribedHuffmanTree }, | 950 | } |
| 951 | .{ .input = "puff21", .err = error.OversubscribedHuffmanTree }, | 951 | test "failing puff10" { |
| 952 | .{ .input = "puff22", .err = error.OversubscribedHuffmanTree }, | 952 | try testFailure(@embedFile("testdata/fuzz/puff10.input"), error.InvalidCode); |
| 953 | .{ .input = "puff23", .err = error.OversubscribedHuffmanTree }, // 35 | 953 | } |
| 954 | .{ .input = "puff24", .err = error.IncompleteHuffmanTree }, | 954 | test "failing puff11" { |
| 955 | .{ .input = "puff25", .err = error.OversubscribedHuffmanTree }, | 955 | try testFailure(@embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch); |
| 956 | .{ .input = "puff26", .err = error.InvalidDynamicBlockHeader }, | 956 | } |
| 957 | .{ .input = "puff27", .err = error.InvalidDynamicBlockHeader }, | 957 | test "failing puff12" { |
| 958 | }; | 958 | try testFailure(@embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader); |
| 959 | | 959 | } |
| 960 | inline for (cases) |c| { | 960 | test "failing puff13" { |
| 961 | var in: Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input")); | 961 | try testFailure(@embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree); |
| 962 | var aw: Writer.Allocating = .init(testing.allocator); | 962 | } |
| 963 | try aw.ensureUnusedCapacity(flate.history_len); | 963 | test "failing puff14" { |
| 964 | defer aw.deinit(); | 964 | try testFailure(@embedFile("testdata/fuzz/puff14.input"), error.EndOfStream); |
| 965 | | 965 | } |
| 966 | var decompress: Decompress = .init(&in, .raw, &.{}); | 966 | test "failing puff15" { |
| 967 | const r = &decompress.reader; | 967 | try testFailure(@embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree); |
| 968 | if (c.err) |expected_err| { | 968 | } |
| 969 | try testing.expectError(error.ReadFailed, r.streamRemaining(&aw.writer)); | 969 | test "failing puff16" { |
| 970 | try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed); | 970 | try testFailure(@embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader); |
| 971 | } else { | 971 | } |
| 972 | _ = try r.streamRemaining(&aw.writer); | 972 | test "failing puff17" { |
| 973 | try testing.expectEqualStrings(c.out, aw.getWritten()); | 973 | try testFailure(@embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode); |
| 974 | } | 974 | } |
| 975 | } | 975 | test "failing fuzz1" { |
| | 976 | try testFailure(@embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader); |
| | 977 | } |
| | 978 | test "failing fuzz2" { |
| | 979 | try testFailure(@embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader); |
| | 980 | } |
| | 981 | test "failing fuzz3" { |
| | 982 | try testFailure(@embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch); |
| | 983 | } |
| | 984 | test "failing fuzz4" { |
| | 985 | try testFailure(@embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree); |
| | 986 | } |
| | 987 | test "failing puff18" { |
| | 988 | try testFailure(@embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree); |
| | 989 | } |
| | 990 | test "failing puff19" { |
| | 991 | try testFailure(@embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree); |
| | 992 | } |
| | 993 | test "failing puff20" { |
| | 994 | try testFailure(@embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree); |
| | 995 | } |
| | 996 | test "failing puff21" { |
| | 997 | try testFailure(@embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree); |
| | 998 | } |
| | 999 | test "failing puff22" { |
| | 1000 | try testFailure(@embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree); |
| | 1001 | } |
| | 1002 | test "failing puff23" { |
| | 1003 | try testFailure(@embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree); |
| | 1004 | } |
| | 1005 | test "failing puff24" { |
| | 1006 | try testFailure(@embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree); |
| | 1007 | } |
| | 1008 | test "failing puff25" { |
| | 1009 | try testFailure(@embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree); |
| | 1010 | } |
| | 1011 | test "failing puff26" { |
| | 1012 | try testFailure(@embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader); |
| | 1013 | } |
| | 1014 | test "failing puff27" { |
| | 1015 | try testFailure(@embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader); |
| 976 | } | 1016 | } |
| 977 | | 1017 | |
| 978 | test "bug 18966" { | 1018 | fn testFailure(in: []const u8, expected_err: anyerror) !void { |
| 979 | const input = @embedFile("testdata/fuzz/bug_18966.input"); | 1019 | var reader: Reader = .fixed(in); |
| 980 | const expect = @embedFile("testdata/fuzz/bug_18966.expect"); | | |
| 981 | | | |
| 982 | var in: Reader = .fixed(input); | | |
| 983 | var aw: Writer.Allocating = .init(testing.allocator); | 1020 | var aw: Writer.Allocating = .init(testing.allocator); |
| 984 | try aw.ensureUnusedCapacity(flate.history_len); | 1021 | try aw.ensureUnusedCapacity(flate.history_len); |
| 985 | defer aw.deinit(); | 1022 | defer aw.deinit(); |
| 986 | | 1023 | |
| 987 | var decompress: Decompress = .init(&in, .gzip, &.{}); | 1024 | var decompress: Decompress = .init(&reader, .raw, &.{}); |
| 988 | const r = &decompress.reader; | 1025 | try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer)); |
| 989 | _ = try r.streamRemaining(&aw.writer); | 1026 | try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed); |
| 990 | try testing.expectEqualStrings(expect, aw.getWritten()); | 1027 | } |
| | 1028 | |
| | 1029 | test "deflate-stream" { |
| | 1030 | try testDecompress( |
| | 1031 | .raw, |
| | 1032 | @embedFile("testdata/fuzz/deflate-stream.input"), |
| | 1033 | @embedFile("testdata/fuzz/deflate-stream.expect"), |
| | 1034 | ); |
| | 1035 | } |
| | 1036 | |
| | 1037 | test "empty-distance-alphabet01" { |
| | 1038 | try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), ""); |
| | 1039 | } |
| | 1040 | |
| | 1041 | test "empty-distance-alphabet02" { |
| | 1042 | try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet02.input"), ""); |
| | 1043 | } |
| | 1044 | |
| | 1045 | test "puff03" { |
| | 1046 | try testDecompress(.raw, @embedFile("testdata/fuzz/puff03.input"), &.{0xa}); |
| | 1047 | } |
| | 1048 | |
| | 1049 | test "puff09" { |
| | 1050 | try testDecompress(.raw, @embedFile("testdata/fuzz/puff09.input"), "P"); |
| | 1051 | } |
| | 1052 | |
| | 1053 | test "bug 18966" { |
| | 1054 | try testDecompress( |
| | 1055 | .gzip, |
| | 1056 | @embedFile("testdata/fuzz/bug_18966.input"), |
| | 1057 | @embedFile("testdata/fuzz/bug_18966.expect"), |
| | 1058 | ); |
| 991 | } | 1059 | } |
| 992 | | 1060 | |
| 993 | test "reading into empty buffer" { | 1061 | test "reading into empty buffer" { |
| ... | @@ -1130,21 +1198,13 @@ test "zlib should not overshoot" { | ... | @@ -1130,21 +1198,13 @@ test "zlib should not overshoot" { |
| 1130 | var out: [128]u8 = undefined; | 1198 | var out: [128]u8 = undefined; |
| 1131 | | 1199 | |
| 1132 | { | 1200 | { |
| 1133 | const n = try decompress.reader.readSliceShort(out[0..]); | 1201 | const n = try decompress.reader.readSliceShort(&out); |
| 1134 | | | |
| 1135 | // Expected decompressed data | | |
| 1136 | try std.testing.expectEqual(46, n); | 1202 | try std.testing.expectEqual(46, n); |
| 1137 | try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]); | 1203 | 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()); | | |
| 1144 | } | 1204 | } |
| 1145 | | 1205 | |
| 1146 | // 4 bytes after compressed chunk are available in reader. | 1206 | // 4 bytes after compressed chunk are available in reader. |
| 1147 | const n = try reader.readSliceShort(out[0..]); | 1207 | const n = try reader.readSliceShort(&out); |
| 1148 | try std.testing.expectEqual(n, 4); | 1208 | try std.testing.expectEqual(n, 4); |
| 1149 | try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]); | 1209 | try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]); |
| 1150 | } | 1210 | } |