| ... | ... | @@ -909,85 +909,153 @@ test "zlib decompress non compressed block (type 0)" { |
| 909 | 909 | }, "Hello world\n"); |
| 910 | 910 | } |
| 911 | 911 | |
| 912 | | test "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 | | } |
| 912 | test "failing end-of-stream" { |
| 913 | try testFailure(@embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream); |
| 914 | } |
| 915 | test "failing invalid-distance" { |
| 916 | try testFailure(@embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch); |
| 917 | } |
| 918 | test "failing invalid-tree01" { |
| 919 | try testFailure(@embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree); |
| 920 | } |
| 921 | test "failing invalid-tree02" { |
| 922 | try testFailure(@embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree); |
| 923 | } |
| 924 | test "failing invalid-tree03" { |
| 925 | try testFailure(@embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree); |
| 926 | } |
| 927 | test "failing lengths-overflow" { |
| 928 | try testFailure(@embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader); |
| 929 | } |
| 930 | test "failing out-of-codes" { |
| 931 | try testFailure(@embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode); |
| 932 | } |
| 933 | test "failing puff01" { |
| 934 | try testFailure(@embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen); |
| 935 | } |
| 936 | test "failing puff02" { |
| 937 | try testFailure(@embedFile("testdata/fuzz/puff02.input"), error.EndOfStream); |
| 938 | } |
| 939 | test "failing puff04" { |
| 940 | try testFailure(@embedFile("testdata/fuzz/puff04.input"), error.InvalidCode); |
| 941 | } |
| 942 | test "failing puff05" { |
| 943 | try testFailure(@embedFile("testdata/fuzz/puff05.input"), error.EndOfStream); |
| 944 | } |
| 945 | test "failing puff06" { |
| 946 | try testFailure(@embedFile("testdata/fuzz/puff06.input"), error.EndOfStream); |
| 947 | } |
| 948 | test "failing puff08" { |
| 949 | try testFailure(@embedFile("testdata/fuzz/puff08.input"), error.InvalidCode); |
| 950 | } |
| 951 | test "failing puff10" { |
| 952 | try testFailure(@embedFile("testdata/fuzz/puff10.input"), error.InvalidCode); |
| 953 | } |
| 954 | test "failing puff11" { |
| 955 | try testFailure(@embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch); |
| 956 | } |
| 957 | test "failing puff12" { |
| 958 | try testFailure(@embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader); |
| 959 | } |
| 960 | test "failing puff13" { |
| 961 | try testFailure(@embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree); |
| 962 | } |
| 963 | test "failing puff14" { |
| 964 | try testFailure(@embedFile("testdata/fuzz/puff14.input"), error.EndOfStream); |
| 965 | } |
| 966 | test "failing puff15" { |
| 967 | try testFailure(@embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree); |
| 968 | } |
| 969 | test "failing puff16" { |
| 970 | try testFailure(@embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader); |
| 971 | } |
| 972 | test "failing puff17" { |
| 973 | try testFailure(@embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode); |
| 974 | } |
| 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" { |
| 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); |
| 1018 | fn testFailure(in: []const u8, expected_err: anyerror) !void { |
| 1019 | var reader: Reader = .fixed(in); |
| 983 | 1020 | var aw: Writer.Allocating = .init(testing.allocator); |
| 984 | 1021 | try aw.ensureUnusedCapacity(flate.history_len); |
| 985 | 1022 | defer aw.deinit(); |
| 986 | 1023 | |
| 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 | |
| 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 | 1061 | test "reading into empty buffer" { |
| ... | ... | @@ -1130,21 +1198,13 @@ test "zlib should not overshoot" { |
| 1130 | 1198 | var out: [128]u8 = undefined; |
| 1131 | 1199 | |
| 1132 | 1200 | { |
| 1133 | | const n = try decompress.reader.readSliceShort(out[0..]); |
| 1134 | | |
| 1135 | | // Expected decompressed data |
| 1201 | const n = try decompress.reader.readSliceShort(&out); |
| 1136 | 1202 | try std.testing.expectEqual(46, n); |
| 1137 | 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 | 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 | 1208 | try std.testing.expectEqual(n, 4); |
| 1149 | 1209 | try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]); |
| 1150 | 1210 | } |