From 6219c015d8e8c958d96e5caa5ef0dbab9c414996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Fri, 8 Aug 2025 16:54:25 +0200 Subject: [PATCH] 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. --- lib/std/Io/Writer.zig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index dd3994c413..86614e6254 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -317,13 +317,14 @@ test "fixed buffer flush" { /// Calls `VTable.drain` but hides the last `preserve_len` bytes from the /// implementation, keeping them buffered. pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void { - const temp_end = w.end -| preserve_len; - const preserved = w.buffer[temp_end..w.end]; - w.end = temp_end; - defer w.end += preserved.len; + const preserved_head = w.end -| preserve_len; + const preserved_tail = w.end; + const preserved_len = preserved_tail - preserved_head; + w.end = preserved_head; + defer w.end += preserved_len; assert(0 == try w.vtable.drain(w, &.{""}, 1)); - assert(w.end <= temp_end + preserved.len); - @memmove(w.buffer[w.end..][0..preserved.len], preserved); + assert(w.end <= preserved_head + preserved_len); + @memmove(w.buffer[w.end..][0..preserved_len], w.buffer[preserved_head..preserved_tail]); } pub fn unusedCapacitySlice(w: *const Writer) []u8 {