authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2025-08-08 16:54:25+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-08 12:56:26-07:00
log6219c015d8e8c958d96e5caa5ef0dbab9c414996
tree67b90037ac1616daa1becaad8dcbe0a1968b170f
parent3ee4252183e92ee8ec51c9ba8631bd9524e26b1f

Io.Writer fix dangling pointer

While underlying writer is Allocating writer buffer can grow in vtable.drain call. We should not hold pointer to the buffer before that call and use it after. This remembers positions instead of holding reference.

1 files changed, 7 insertions(+), 6 deletions(-)

lib/std/Io/Writer.zig+7-6
...@@ -317,13 +317,14 @@ test "fixed buffer flush" {...@@ -317,13 +317,14 @@ test "fixed buffer flush" {
317/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the317/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the
318/// implementation, keeping them buffered.318/// implementation, keeping them buffered.
319pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {319pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {
320 const temp_end = w.end -| preserve_len;320 const preserved_head = w.end -| preserve_len;
321 const preserved = w.buffer[temp_end..w.end];321 const preserved_tail = w.end;
322 w.end = temp_end;322 const preserved_len = preserved_tail - preserved_head;
323 defer w.end += preserved.len;323 w.end = preserved_head;
324 defer w.end += preserved_len;
324 assert(0 == try w.vtable.drain(w, &.{""}, 1));325 assert(0 == try w.vtable.drain(w, &.{""}, 1));
325 assert(w.end <= temp_end + preserved.len);326 assert(w.end <= preserved_head + preserved_len);
326 @memmove(w.buffer[w.end..][0..preserved.len], preserved);327 @memmove(w.buffer[w.end..][0..preserved_len], w.buffer[preserved_head..preserved_tail]);
327}328}
328329
329pub fn unusedCapacitySlice(w: *const Writer) []u8 {330pub fn unusedCapacitySlice(w: *const Writer) []u8 {