From 0674b51453d5631f400936b4da7c74788f745e90 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Sat, 28 Mar 2020 00:12:40 -0500 Subject: [PATCH] In getCwdAlloc, geometrically allocate larger buffers to find an appropriate size. --- lib/std/process.zig | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/std/process.zig b/lib/std/process.zig index 4e602a63cb..85d3ae2ecb 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -21,10 +21,28 @@ pub fn getCwd(out_buffer: []u8) ![]u8 { /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { - // TODO(#4812): Consider looping with larger and larger buffers to handle - // overlong paths. - var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - return mem.dupe(allocator, u8, try os.getcwd(&buf)); + // The use of MAX_PATH_BYTES here is just a heuristic: most paths will fit + // in stack_buf, avoiding an extra allocation in the common case. + var stack_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + var heap_buf: ?[]u8 = null; + defer if (heap_buf) |buf| allocator.free(buf); + + var current_buf: []u8 = &stack_buf; + while (true) { + if (os.getcwd(current_buf)) |slice| { + return mem.dupe(allocator, u8, slice); + } else |err| switch(err) { + error.NameTooLong => { + // The path is too long to fit in stack_buf. Allocate geometrically + // increasing buffers until we find one that works + const new_capacity = current_buf.len * 2; + if (heap_buf) |buf| allocator.free(buf); + current_buf = try allocator.alloc(u8, new_capacity); + heap_buf = current_buf; + }, + else => return err, + } + } } test "getCwdAlloc" {