authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-16 23:43:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-17 09:26:31-07:00
log5784500572e3d12b0342cc5b09210c1d1f49edc5
treeef43650246d244c7b7f1e1b1b61e0e7df67a6b5e
parent86699acbb951ceed3ecdd3bd93a00ceb02028361

std.Io.Reader: fix readSliceShort with smaller buffer than Reader

closes #24443

1 files changed, 30 insertions(+), 36 deletions(-)

lib/std/Io/Reader.zig+30-36
......@@ -593,48 +593,29 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
593593/// See also:
594594/// * `readSliceAll`
595595pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
596 const in_buffer = r.buffer[r.seek..r.end];
597 const copy_len = @min(buffer.len, in_buffer.len);
598 @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
599 if (buffer.len - copy_len == 0) {
600 r.seek += copy_len;
601 return buffer.len;
602 }
603 var i: usize = copy_len;
604 r.end = 0;
605 r.seek = 0;
596 var i: usize = 0;
606597 while (true) {
598 const buffer_contents = r.buffer[r.seek..r.end];
599 const dest = buffer[i..];
600 const copy_len = @min(dest.len, buffer_contents.len);
601 @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]);
602 if (dest.len - copy_len == 0) {
603 @branchHint(.likely);
604 r.seek += copy_len;
605 return buffer.len;
606 }
607 i += copy_len;
608 r.end = 0;
609 r.seek = 0;
607610 const remaining = buffer[i..];
608 var wrapper: Writer.VectorWrapper = .{
609 .it = .{
610 .first = remaining,
611 .last = r.buffer,
612 },
613 .writer = .{
614 .buffer = if (remaining.len >= r.buffer.len) remaining else r.buffer,
615 .vtable = Writer.VectorWrapper.vtable,
616 },
617 };
618 const n = r.vtable.stream(r, &wrapper.writer, .unlimited) catch |err| switch (err) {
619 error.WriteFailed => {
620 if (!wrapper.used) {
621 assert(r.seek == 0);
622 r.seek = remaining.len;
623 r.end = wrapper.writer.end;
624 @memcpy(remaining, r.buffer[0..remaining.len]);
625 }
626 return buffer.len;
627 },
611 const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) {
628612 error.EndOfStream => return i,
629613 error.ReadFailed => return error.ReadFailed,
630614 };
631 if (n < remaining.len) {
632 i += n;
633 continue;
634 }
635 r.end = n - remaining.len;
636 return buffer.len;
615 if (new_remaining_len == 0) return buffer.len;
616 i += remaining.len - new_remaining_len;
637617 }
618 return buffer.len;
638619}
639620
640621/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
......@@ -1640,6 +1621,19 @@ test readSliceShort {
16401621 try testing.expectEqual(0, try r.readSliceShort(&buf));
16411622}
16421623
1624test "readSliceShort with smaller buffer than Reader" {
1625 var reader_buf: [15]u8 = undefined;
1626 const str = "This is a test";
1627 var one_byte_stream: testing.Reader = .init(&reader_buf, &.{
1628 .{ .buffer = str },
1629 });
1630 one_byte_stream.artificial_limit = .limited(1);
1631
1632 var buf: [14]u8 = undefined;
1633 try testing.expectEqual(14, try one_byte_stream.interface.readSliceShort(&buf));
1634 try testing.expectEqualStrings(str, &buf);
1635}
1636
16431637test readVec {
16441638 var r: Reader = .fixed(std.ascii.letters);
16451639 var flat_buffer: [52]u8 = undefined;