readAlloc does not update r.interface.seek and r.interface.end

Hi folks, I’m finding a confusing behaviour with the new IO reader API, during my zig development. Let me know if I’m missing something.

I’m trying to read the headers of a kernel file using a buffer instead of a file reader:

    var gpa = std.heap.DebugAllocator(.{}){};
    defer _ = gpa.deinit();
    const alloc = gpa.allocator();
  
    var file = try std.Io.Dir.cwd().openFile(
        io,
        kernel_file_path,
        .{.allow_directory = true}
    );
    defer file.close(io);

    var read_buf: [4096]u8 = undefined;
    var reader = file.reader(io, &read_buf);
    const kernel_buf = try reader.interface.readAlloc(alloc, kernel_stats.size);
    defer alloc.free(kernel_buf);

    std.debug.print(\\
    \\seek:             {d}
    \\end:              {d}
    \\kernel size:      {d}
    \\
    , .{reader.interface.seek, reader.interface.end, kernel_stats.size}); 
    const header = try std.elf.Header.read(&reader.interface);

    std.debug.print(
    \\seek:             {d}
    \\end:              {d}
    \\kernel size:      {d}
    \\
    , .{reader.interface.seek, reader.interface.end, kernel_stats.size}); 

    var iter = std.elf.Header.iterateProgramHeadersBuffer(
        &header,     
        kernel_buf
        );

When I run it, I reach an EOS but the r.interface.seek and r.interface.end are not modified.

error: 'test.test.read-parse-kernel' failed:
       HELLOOO
       .{ .handle = -100 }
       seek:             0
       end:              0
       kernel size:      2663757
       /snap/zig/16117/lib/std/Io/File/Reader.zig:267:9: 0x1057889 in readVecPositional (test)
               return error.EndOfStream;
               ^

However std.elf.Header.read(&reader.interface) actually modifies seek/end possitions, if I do it before reading the entire file with readAlloc

error: 'test.test.read-parse-kernel' failed:
       HELLOOO
       .{ .handle = -100 }
       seek:             64
       end:              4096
       kernel size:      2663757

Diving into the source code I saw std.elf.Header.read uses r.peek and readAlloc uses readSliceAll, which ends up using defaultReadVec providing it the allocated buffer.
If my understanding is correct, defaultReadVec, writes to the reader buffer or the provided one, depending whichone is bigger.
In my case the allocated (kernel size) buffer will be bigger so problem may be there?
Anyways I find it confusing when I’m trying to debug it. I expected to see an updated seek/end variable of the reader before reaching EOS.

Any thoughts on it?

seek and end describe the state of the interfaces’ buffer, it is perfectly valid for them to be 0 or any other value at any point.
You should not really be caring what those values are, they are internal to the reader/writer

more specifically readAlloc reads directly into an allocated slice, it wont add any data to the interface’s buffer (this is common but some readers may be different), but it will remove data from it if there is any. If there is no data in the interfaces buffer it is expected that the buffer state would not change.

whereas std.elf.Header.read uses the peek/take api of the reader, which are guaranteed to use the buffer, so it is expected that the buffer state might be different than what it began as.

2 Likes