Commit cc3c4d1069

Jacob Young <jacobly0@users.noreply.github.com>
2025-10-15 05:16:26
windows: workaround kernel race condition in more places
1 parent 595cd89
Changed files (1)
test
standalone
windows_spawn
test/standalone/windows_spawn/main.zig
@@ -71,19 +71,7 @@ pub fn main() anyerror!void {
     try testExec(allocator, "heLLo", "hello from exe\n");
 
     // now rename the exe to not have an extension
-    {
-        var attempt: u5 = 0;
-        while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
-            error.AccessDenied => {
-                if (attempt == 13) return error.AccessDenied;
-                // give the kernel a chance to finish closing the executable handle
-                std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
-                attempt += 1;
-                continue;
-            },
-            else => |e| return e,
-        };
-    }
+    try renameExe(tmp.dir, "hello.exe", "hello");
 
     // with extension should now fail
     try testExecError(error.FileNotFound, allocator, "hello.exe");
@@ -91,7 +79,7 @@ pub fn main() anyerror!void {
     try testExec(allocator, "heLLo", "hello from exe\n");
 
     try tmp.dir.makeDir("something");
-    try tmp.dir.rename("hello", "something/hello.exe");
+    try renameExe(tmp.dir, "hello", "something/hello.exe");
 
     const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });
     defer allocator.free(relative_path_no_ext);
@@ -118,14 +106,14 @@ pub fn main() anyerror!void {
     try testExecError(error.InvalidExe, allocator, "hello");
 
     // If we now rename hello.exe to have no extension, it will behave differently
-    try tmp.dir.rename("hello.exe", "hello");
+    try renameExe(tmp.dir, "hello.exe", "hello");
 
     // Now, trying to execute it without an extension should treat InvalidExe as recoverable
     // and skip over it and find hello.bat and execute that
     try testExec(allocator, "hello", "hello from bat\r\n");
 
     // If we rename the invalid exe to something else
-    try tmp.dir.rename("hello", "goodbye");
+    try renameExe(tmp.dir, "hello", "goodbye");
     // Then we should now get FileNotFound when trying to execute 'goodbye',
     // since that is what the original error will be after searching for 'goodbye'
     // in the cwd. It will try to execute 'goodbye' from the PATH but the InvalidExe error
@@ -151,7 +139,7 @@ pub fn main() anyerror!void {
     try testExec(allocator, "hello", "hello from bat\r\n");
 
     // If we rename something/hello.exe to something/goodbye.exe
-    try tmp.dir.rename("something/hello.exe", "something/goodbye.exe");
+    try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");
     // And try to execute goodbye, then the one in something should be found
     // since the one in cwd is an invalid executable
     try testExec(allocator, "goodbye", "hello from exe\n");
@@ -196,7 +184,7 @@ pub fn main() anyerror!void {
     var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
     defer subdir_cwd.close();
 
-    try tmp.dir.rename("something/goodbye.exe", "hello.exe");
+    try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");
     try subdir_cwd.setAsCwd();
 
     // clear the PATH again
@@ -229,3 +217,17 @@ fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]co
     try std.testing.expectEqualStrings("", result.stderr);
     try std.testing.expectEqualStrings(expected_stdout, result.stdout);
 }
+
+fn renameExe(dir: std.fs.Dir, old_sub_path: []const u8, new_sub_path: []const u8) !void {
+    var attempt: u5 = 0;
+    while (true) break dir.rename(old_sub_path, new_sub_path) catch |err| switch (err) {
+        error.AccessDenied => {
+            if (attempt == 13) return error.AccessDenied;
+            // give the kernel a chance to finish closing the executable handle
+            std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
+            attempt += 1;
+            continue;
+        },
+        else => |e| return e,
+    };
+}