| author | |
| committer | |
| log | 08f0780cb2e33ae4d1f7059b6f173459b46adc25 |
| tree | e5428115a5ebb4afb1979289b0060b2cafcc512b |
| parent | e252e6c696192729e576fffbd26991bd4b19e434 |
The previous code assumed that `initFrame` during the `new_frame` state would always result in the `in_frame` state, but that's not always the case. `initFrame` can also result in the `skippable_frame` state, which would lead to access of union field 'in_frame' while field 'skipping_frame' is active.
Now, the switch is re-entered with the updated state so either case is handled appropriately.
Fixes the crashes from https://github.com/ziglang/zig/issues/248172 files changed, 11 insertions(+), 9 deletions(-)
lib/std/compress/zstd.zig+9| ... | ... | @@ -156,3 +156,12 @@ test "declared raw literals size too large" { |
| 156 | 156 | // block can't be valid as it is a raw literals block. |
| 157 | 157 | try testExpectDecompressError(error.MalformedLiteralsSection, input_raw); |
| 158 | 158 | } |
| 159 | ||
| 160 | test "skippable frame" { | |
| 161 | const input_raw = | |
| 162 | "\x50\x2a\x4d\x18" ++ // min magic number for a skippable frame | |
| 163 | "\x02\x00\x00\x00" ++ // number of bytes to skip | |
| 164 | "\xFF\xFF"; // the bytes that are skipped | |
| 165 | ||
| 166 | try testExpectDecompress("", input_raw); | |
| 167 | } |
lib/std/compress/zstd/Decompress.zig+2-9| ... | ... | @@ -155,7 +155,7 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
| 155 | 155 | const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); |
| 156 | 156 | const in = d.input; |
| 157 | 157 | |
| 158 | switch (d.state) { | |
| 158 | state: switch (d.state) { | |
| 159 | 159 | .new_frame => { |
| 160 | 160 | // Only return EndOfStream when there are exactly 0 bytes remaining on the |
| 161 | 161 | // frame magic. Any partial magic bytes should be considered a failure. |
| ... | ... | @@ -174,14 +174,7 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
| 174 | 174 | d.err = err; |
| 175 | 175 | return error.ReadFailed; |
| 176 | 176 | }; |
| 177 | return readInFrame(d, w, limit, &d.state.in_frame) catch |err| switch (err) { | |
| 178 | error.ReadFailed => return error.ReadFailed, | |
| 179 | error.WriteFailed => return error.WriteFailed, | |
| 180 | else => |e| { | |
| 181 | d.err = e; | |
| 182 | return error.ReadFailed; | |
| 183 | }, | |
| 184 | }; | |
| 177 | continue :state d.state; | |
| 185 | 178 | }, |
| 186 | 179 | .in_frame => |*in_frame| { |
| 187 | 180 | return readInFrame(d, w, limit, in_frame) catch |err| switch (err) { |