Skip to content

std.io.Writer.Hashing + streamRemaining not correct if read/discard has happened #25187

@ghost

Description

Zig Version

0.15.2

Steps to Reproduce and Observed Behavior

test "Old vs New vs Stream" {
    // dd if=/dev/urandom of=/tmp/test bs=1048576 count=4
    // old
    const sha = std.crypto.hash.sha3;
    var old: [32]u8 = undefined;
    {
        var e = sha.Sha3_256.init(.{});
        var read_buf: [4096]u8 = undefined;
        var file = try std.fs.openFileAbsolute("/tmp/test", .{});
        defer file.close();
        try file.seekBy(8); // Remove this in all cases and it works
        while (true) {
            const read = try file.readAll(&read_buf);
            if (read == 0) break;
            e.update(read_buf[0..read]);
        }
        e.final(&old);
    }

    // new
    var new: [32]u8 = undefined;
    {
        var e = sha.Sha3_256.init(.{});
        var read_buf: [4096]u8 = undefined;
        var file = try std.fs.openFileAbsolute("/tmp/test", .{});
        defer file.close();
        var reader = file.reader(&read_buf);
        try reader.interface.discardAll(8); // Remove this in all cases and it works
        while (true) {
            reader.interface.fillMore() catch |err| {
                switch (err) {
                    io.Reader.Error.EndOfStream => break,
                    else => return err,
                }
            };
            e.update(reader.interface.buffered());
            try reader.interface.discardAll(reader.interface.bufferedLen());
        }
        e.final(&new);
    }

    // stream ----> This is the problem case
    var stream: [32]u8 = undefined;
    {
        var read_buf: [4096]u8 = undefined;
        var file = try std.fs.openFileAbsolute("/tmp/test", .{});
        defer file.close();
        var reader = file.reader(&read_buf);
        try reader.interface.discardAll(8); // Remove this in all cases and it works
        var buffer: [config.BLOCK_SIZE]u8 = undefined;
        var e = std.io.Writer.Hashing(sha.Sha3_256).init(&buffer);
        _ = try reader.interface.streamRemaining(&e.writer);
        e.hasher.final(&stream);
    }

    try t.expect(mem.eql(u8, &new, &old));
    try t.expect(mem.eql(u8, &new, &stream));
}
error: 'scanner.test.Old vs New vs Hashing' 
Test.Old vs New vs Hashing (test)
    try t.expect(mem.eql(u8, &new, &stream));

Expected Behavior

If we are already a bit into the stream streamRemaining() (mentioned in #25173) will not work correctly. I added the implementation new which I am actually using, because it avoids double-buffering, too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavior

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions