Skip to content

Commit 08f0780

Browse files
squeek502andrewrk
authored andcommitted
zstd.Decompress.stream: Fix handling of skippable frames in new_frame state
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 #24817
1 parent e252e6c commit 08f0780

File tree

2 files changed

+11
-9
lines changed

2 files changed

+11
-9
lines changed

lib/std/compress/zstd.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,12 @@ test "declared raw literals size too large" {
156156
// block can't be valid as it is a raw literals block.
157157
try testExpectDecompressError(error.MalformedLiteralsSection, input_raw);
158158
}
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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
155155
const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
156156
const in = d.input;
157157

158-
switch (d.state) {
158+
state: switch (d.state) {
159159
.new_frame => {
160160
// Only return EndOfStream when there are exactly 0 bytes remaining on the
161161
// 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 {
174174
d.err = err;
175175
return error.ReadFailed;
176176
};
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;
185178
},
186179
.in_frame => |*in_frame| {
187180
return readInFrame(d, w, limit, in_frame) catch |err| switch (err) {

0 commit comments

Comments
 (0)