| ... | ... | @@ -271,10 +271,9 @@ pub const DecodeState = struct { |
| 271 | 271 | literals: LiteralsSection, |
| 272 | 272 | sequence: Sequence, |
| 273 | 273 | ) !void { |
| 274 | | try self.decodeLiteralsSlice(dest[write_pos..], literals, sequence.literal_length); |
| 274 | if (sequence.offset > write_pos + sequence.literal_length) return error.MalformedSequence; |
| 275 | 275 | |
| 276 | | // TODO: should we validate offset against max_window_size? |
| 277 | | assert(sequence.offset <= write_pos + sequence.literal_length); |
| 276 | try self.decodeLiteralsSlice(dest[write_pos..], literals, sequence.literal_length); |
| 278 | 277 | const copy_start = write_pos + sequence.literal_length - sequence.offset; |
| 279 | 278 | const copy_end = copy_start + sequence.match_length; |
| 280 | 279 | // NOTE: we ignore the usage message for std.mem.copy and copy with dest.ptr >= src.ptr |
| ... | ... | @@ -288,8 +287,9 @@ pub const DecodeState = struct { |
| 288 | 287 | literals: LiteralsSection, |
| 289 | 288 | sequence: Sequence, |
| 290 | 289 | ) !void { |
| 290 | if (sequence.offset > dest.data.len) return error.MalformedSequence; |
| 291 | |
| 291 | 292 | try self.decodeLiteralsRingBuffer(dest, literals, sequence.literal_length); |
| 292 | | // TODO: check that ring buffer window is full enough for match copies |
| 293 | 293 | const copy_slice = dest.sliceAt(dest.write_index + dest.data.len - sequence.offset, sequence.match_length); |
| 294 | 294 | // TODO: would std.mem.copy and figuring out dest slice be better/faster? |
| 295 | 295 | for (copy_slice.first) |b| dest.writeAssumeCapacity(b); |
| ... | ... | @@ -302,9 +302,13 @@ pub const DecodeState = struct { |
| 302 | 302 | write_pos: usize, |
| 303 | 303 | literals: LiteralsSection, |
| 304 | 304 | bit_reader: anytype, |
| 305 | sequence_size_limit: usize, |
| 305 | 306 | last_sequence: bool, |
| 306 | 307 | ) !usize { |
| 307 | 308 | const sequence = try self.nextSequence(bit_reader); |
| 309 | const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length; |
| 310 | if (sequence_length > sequence_size_limit) return error.MalformedSequence; |
| 311 | |
| 308 | 312 | try self.executeSequenceSlice(dest, write_pos, literals, sequence); |
| 309 | 313 | log.debug("sequence decompressed into '{x}'", .{ |
| 310 | 314 | std.fmt.fmtSliceHexUpper(dest[write_pos .. write_pos + sequence.literal_length + sequence.match_length]), |
| ... | ... | @@ -314,7 +318,7 @@ pub const DecodeState = struct { |
| 314 | 318 | try self.updateState(.match, bit_reader); |
| 315 | 319 | try self.updateState(.offset, bit_reader); |
| 316 | 320 | } |
| 317 | | return sequence.match_length + sequence.literal_length; |
| 321 | return sequence_length; |
| 318 | 322 | } |
| 319 | 323 | |
| 320 | 324 | pub fn decodeSequenceRingBuffer( |
| ... | ... | @@ -322,12 +326,15 @@ pub const DecodeState = struct { |
| 322 | 326 | dest: *RingBuffer, |
| 323 | 327 | literals: LiteralsSection, |
| 324 | 328 | bit_reader: anytype, |
| 329 | sequence_size_limit: usize, |
| 325 | 330 | last_sequence: bool, |
| 326 | 331 | ) !usize { |
| 327 | 332 | const sequence = try self.nextSequence(bit_reader); |
| 333 | const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length; |
| 334 | if (sequence_length > sequence_size_limit) return error.MalformedSequence; |
| 335 | |
| 328 | 336 | try self.executeSequenceRingBuffer(dest, literals, sequence); |
| 329 | 337 | if (std.options.log_level == .debug) { |
| 330 | | const sequence_length = sequence.literal_length + sequence.match_length; |
| 331 | 338 | const written_slice = dest.sliceLast(sequence_length); |
| 332 | 339 | log.debug("sequence decompressed into '{x}{x}'", .{ |
| 333 | 340 | std.fmt.fmtSliceHexUpper(written_slice.first), |
| ... | ... | @@ -339,7 +346,7 @@ pub const DecodeState = struct { |
| 339 | 346 | try self.updateState(.match, bit_reader); |
| 340 | 347 | try self.updateState(.offset, bit_reader); |
| 341 | 348 | } |
| 342 | | return sequence.match_length + sequence.literal_length; |
| 349 | return sequence_length; |
| 343 | 350 | } |
| 344 | 351 | |
| 345 | 352 | fn nextLiteralMultiStream(self: *DecodeState, literals: LiteralsSection) !void { |
| ... | ... | @@ -717,9 +724,9 @@ pub fn decodeBlock( |
| 717 | 724 | consumed_count: *usize, |
| 718 | 725 | written_count: usize, |
| 719 | 726 | ) !usize { |
| 720 | | const block_maximum_size = 1 << 17; // 128KiB |
| 727 | const block_size_max = @min(1 << 17, dest[written_count..].len); // 128KiB |
| 721 | 728 | const block_size = block_header.block_size; |
| 722 | | if (block_maximum_size < block_size) return error.BlockSizeOverMaximum; |
| 729 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; |
| 723 | 730 | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 724 | 731 | switch (block_header.block_type) { |
| 725 | 732 | .raw => return decodeRawBlock(dest[written_count..], src, block_size, consumed_count), |
| ... | ... | @@ -739,17 +746,21 @@ pub fn decodeBlock( |
| 739 | 746 | |
| 740 | 747 | try decode_state.readInitialFseState(&bit_stream); |
| 741 | 748 | |
| 749 | var sequence_size_limit = block_size_max; |
| 742 | 750 | var i: usize = 0; |
| 743 | 751 | while (i < sequences_header.sequence_count) : (i += 1) { |
| 744 | 752 | log.debug("decoding sequence {d}", .{i}); |
| 753 | const write_pos = written_count + bytes_written; |
| 745 | 754 | const decompressed_size = try decode_state.decodeSequenceSlice( |
| 746 | 755 | dest, |
| 747 | | written_count + bytes_written, |
| 756 | write_pos, |
| 748 | 757 | literals, |
| 749 | 758 | &bit_stream, |
| 759 | sequence_size_limit, |
| 750 | 760 | i == sequences_header.sequence_count - 1, |
| 751 | 761 | ); |
| 752 | 762 | bytes_written += decompressed_size; |
| 763 | sequence_size_limit -= decompressed_size; |
| 753 | 764 | } |
| 754 | 765 | |
| 755 | 766 | bytes_read += bit_stream_bytes.len; |
| ... | ... | @@ -781,10 +792,10 @@ pub fn decodeBlockRingBuffer( |
| 781 | 792 | block_header: frame.ZStandard.Block.Header, |
| 782 | 793 | decode_state: *DecodeState, |
| 783 | 794 | consumed_count: *usize, |
| 784 | | block_size_maximum: usize, |
| 795 | block_size_max: usize, |
| 785 | 796 | ) !usize { |
| 786 | 797 | const block_size = block_header.block_size; |
| 787 | | if (block_size_maximum < block_size) return error.BlockSizeOverMaximum; |
| 798 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; |
| 788 | 799 | // TODO: we probably want to enable safety for release-fast and release-small (or insert custom checks) |
| 789 | 800 | switch (block_header.block_type) { |
| 790 | 801 | .raw => return decodeRawBlockRingBuffer(dest, src, block_size, consumed_count), |
| ... | ... | @@ -804,6 +815,7 @@ pub fn decodeBlockRingBuffer( |
| 804 | 815 | |
| 805 | 816 | try decode_state.readInitialFseState(&bit_stream); |
| 806 | 817 | |
| 818 | var sequence_size_limit = block_size_max; |
| 807 | 819 | var i: usize = 0; |
| 808 | 820 | while (i < sequences_header.sequence_count) : (i += 1) { |
| 809 | 821 | log.debug("decoding sequence {d}", .{i}); |
| ... | ... | @@ -811,9 +823,11 @@ pub fn decodeBlockRingBuffer( |
| 811 | 823 | dest, |
| 812 | 824 | literals, |
| 813 | 825 | &bit_stream, |
| 826 | sequence_size_limit, |
| 814 | 827 | i == sequences_header.sequence_count - 1, |
| 815 | 828 | ); |
| 816 | 829 | bytes_written += decompressed_size; |
| 830 | sequence_size_limit -= decompressed_size; |
| 817 | 831 | } |
| 818 | 832 | |
| 819 | 833 | bytes_read += bit_stream_bytes.len; |