Commit 0674b51453

Jonathan S <gereeter+code@gmail.com>
2020-03-28 06:12:40
In getCwdAlloc, geometrically allocate larger buffers to find an appropriate size.
1 parent ab3931f
Changed files (1)
lib
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" {