Skip to content

Conversation

torque
Copy link
Contributor

@torque torque commented Sep 14, 2025

std.Io.Reader.discardShort will loop infinitely if the read position is at the end of the file.

In std/fs/File.zig:

zig/lib/std/fs/File.zig

Lines 1382 to 1390 in 32a1aab

.positional, .positional_reading => {
const size = r.getSize() catch {
r.mode = r.mode.toStreaming();
return 0;
};
const delta = @min(@intFromEnum(limit), size - pos);
r.pos = pos + delta;
return delta;
},

on L1387, if pos == size then delta == 0, so the function will return 0. Then in std/Io/Reader.zig

zig/lib/std/Io/Reader.zig

Lines 605 to 622 in 32a1aab

pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
const proposed_seek = r.seek + n;
if (proposed_seek <= r.end) {
@branchHint(.likely);
r.seek = proposed_seek;
return n;
}
var remaining = n - (r.end - r.seek);
r.seek = r.end;
while (true) {
const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
error.EndOfStream => return n - remaining,
error.ReadFailed => return error.ReadFailed,
};
remaining -= discard_len;
if (remaining == 0) return n;
}
}

on L615, discard_len will be 0, so remaining will never decrement.

A simple reproduction zig run repro.zig:

pub fn main() !void {
    const file = try std.fs.cwd().openFile("repro.zig", .{});
    var buffer: [4096]u8 = undefined;
    var reader = file.reader(&buffer);
    try reader.interface.discardAll(512);
}

const std = @import("std");

There are probably multiple ways to address this, and I don't know if this is the best one, but I am reasonably confident that infinite looping is not the correct behavior here.

std.Io.Reader.discardShort will loop infinitely if the seek position is
at the end of the file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant