authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-07 14:33:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-07 14:35:08-07:00
logb824ca8494f24b92fb5f84eea64807678315eae3
tree47c2b86f14b7e64614f52940fc773b5186428323
parent2c0aa1c6f551a38ee359065cce09eadb3b34cc2d

Revert "Fix infinite loop in Reader.Limited"

This reverts commit 27aba2d776caf59bb6569934626af587fdba9c75. I'd like to review this contribution more carefully, particularly with the alternate implementation that is also open as a pull request (#25109). Reopens #25093

1 files changed, 3 insertions(+), 63 deletions(-)

lib/std/Io/Reader/Limited.zig+3-63
...@@ -28,11 +28,9 @@ pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited {...@@ -28,11 +28,9 @@ pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited {
28fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {28fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
29 const l: *Limited = @fieldParentPtr("interface", r);29 const l: *Limited = @fieldParentPtr("interface", r);
30 const combined_limit = limit.min(l.remaining);30 const combined_limit = limit.min(l.remaining);
31 if (combined_limit.nonzero()) {31 const n = try l.unlimited.stream(w, combined_limit);
32 const n = try l.unlimited.stream(w, combined_limit);32 l.remaining = l.remaining.subtract(n).?;
33 l.remaining = l.remaining.subtract(n).?;33 return n;
34 return n;
35 } else return error.EndOfStream;
36}34}
3735
38test stream {36test stream {
...@@ -51,64 +49,6 @@ test stream {...@@ -51,64 +49,6 @@ test stream {
51 try std.testing.expectEqualStrings("test", result_buf[0..streamed]);49 try std.testing.expectEqualStrings("test", result_buf[0..streamed]);
52}50}
5351
54test "readSliceAll from infinite source" {
55 const InfSource = struct {
56 reader: std.Io.Reader,
57
58 pub fn init(buffer: []u8) @This() {
59 return @This(){
60 .reader = .{
61 .vtable = &.{
62 .stream = streamA,
63 },
64 .buffer = buffer,
65 .seek = 0,
66 .end = 0,
67 },
68 };
69 }
70
71 fn streamA(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
72 _ = io_reader;
73
74 std.debug.assert(limit.nonzero());
75
76 const n_bytes_remaining = limit.minInt(2);
77 for (0..n_bytes_remaining) |_| {
78 try w.writeByte('A');
79 }
80 return n_bytes_remaining;
81 }
82 };
83
84 // Exact size
85 {
86 var inf_buf: [10]u8 = undefined;
87 var inf_stream = InfSource.init(&inf_buf);
88
89 var limit_buf: [2]u8 = undefined;
90 var limited: std.Io.Reader.Limited = .init(&inf_stream.reader, .limited(2), &limit_buf);
91 const limited_reader = &limited.interface;
92
93 var out_buffer: [2]u8 = undefined;
94 try std.testing.expectEqual({}, limited_reader.readSliceAll(&out_buffer));
95 try std.testing.expectEqualStrings("AA", &out_buffer);
96 }
97
98 // Too large
99 {
100 var inf_buf: [10]u8 = undefined;
101 var inf_stream = InfSource.init(&inf_buf);
102
103 var limit_buf: [2]u8 = undefined;
104 var limited: std.Io.Reader.Limited = .init(&inf_stream.reader, .limited(2), &limit_buf);
105 const limited_reader = &limited.interface;
106
107 var out_buffer: [8]u8 = undefined;
108 try std.testing.expectError(error.EndOfStream, limited_reader.readSliceAll(&out_buffer));
109 }
110}
111
112fn discard(r: *Reader, limit: Limit) Reader.Error!usize {52fn discard(r: *Reader, limit: Limit) Reader.Error!usize {
113 const l: *Limited = @fieldParentPtr("interface", r);53 const l: *Limited = @fieldParentPtr("interface", r);
114 const combined_limit = limit.min(l.remaining);54 const combined_limit = limit.min(l.remaining);