Skip to content

Commit cc3c4d1

Browse files
committed
windows: workaround kernel race condition in more places
1 parent 595cd89 commit cc3c4d1

1 file changed

Lines changed: 20 additions & 18 deletions

File tree

test/standalone/windows_spawn/main.zig

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,27 +71,15 @@ pub fn main() anyerror!void {
7171
try testExec(allocator, "heLLo", "hello from exe\n");
7272

7373
// now rename the exe to not have an extension
74-
{
75-
var attempt: u5 = 0;
76-
while (true) break tmp.dir.rename("hello.exe", "hello") catch |err| switch (err) {
77-
error.AccessDenied => {
78-
if (attempt == 13) return error.AccessDenied;
79-
// give the kernel a chance to finish closing the executable handle
80-
std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
81-
attempt += 1;
82-
continue;
83-
},
84-
else => |e| return e,
85-
};
86-
}
74+
try renameExe(tmp.dir, "hello.exe", "hello");
8775

8876
// with extension should now fail
8977
try testExecError(error.FileNotFound, allocator, "hello.exe");
9078
// without extension should succeed (case insensitive)
9179
try testExec(allocator, "heLLo", "hello from exe\n");
9280

9381
try tmp.dir.makeDir("something");
94-
try tmp.dir.rename("hello", "something/hello.exe");
82+
try renameExe(tmp.dir, "hello", "something/hello.exe");
9583

9684
const relative_path_no_ext = try std.fs.path.join(allocator, &.{ tmp_relative_path, "something/hello" });
9785
defer allocator.free(relative_path_no_ext);
@@ -118,14 +106,14 @@ pub fn main() anyerror!void {
118106
try testExecError(error.InvalidExe, allocator, "hello");
119107

120108
// If we now rename hello.exe to have no extension, it will behave differently
121-
try tmp.dir.rename("hello.exe", "hello");
109+
try renameExe(tmp.dir, "hello.exe", "hello");
122110

123111
// Now, trying to execute it without an extension should treat InvalidExe as recoverable
124112
// and skip over it and find hello.bat and execute that
125113
try testExec(allocator, "hello", "hello from bat\r\n");
126114

127115
// If we rename the invalid exe to something else
128-
try tmp.dir.rename("hello", "goodbye");
116+
try renameExe(tmp.dir, "hello", "goodbye");
129117
// Then we should now get FileNotFound when trying to execute 'goodbye',
130118
// since that is what the original error will be after searching for 'goodbye'
131119
// 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 {
151139
try testExec(allocator, "hello", "hello from bat\r\n");
152140

153141
// If we rename something/hello.exe to something/goodbye.exe
154-
try tmp.dir.rename("something/hello.exe", "something/goodbye.exe");
142+
try renameExe(tmp.dir, "something/hello.exe", "something/goodbye.exe");
155143
// And try to execute goodbye, then the one in something should be found
156144
// since the one in cwd is an invalid executable
157145
try testExec(allocator, "goodbye", "hello from exe\n");
@@ -196,7 +184,7 @@ pub fn main() anyerror!void {
196184
var subdir_cwd = try tmp.dir.openDir(denormed_something_subdir_wtf8, .{});
197185
defer subdir_cwd.close();
198186

199-
try tmp.dir.rename("something/goodbye.exe", "hello.exe");
187+
try renameExe(tmp.dir, "something/goodbye.exe", "hello.exe");
200188
try subdir_cwd.setAsCwd();
201189

202190
// clear the PATH again
@@ -229,3 +217,17 @@ fn testExecWithCwd(allocator: std.mem.Allocator, command: []const u8, cwd: ?[]co
229217
try std.testing.expectEqualStrings("", result.stderr);
230218
try std.testing.expectEqualStrings(expected_stdout, result.stdout);
231219
}
220+
221+
fn renameExe(dir: std.fs.Dir, old_sub_path: []const u8, new_sub_path: []const u8) !void {
222+
var attempt: u5 = 0;
223+
while (true) break dir.rename(old_sub_path, new_sub_path) catch |err| switch (err) {
224+
error.AccessDenied => {
225+
if (attempt == 13) return error.AccessDenied;
226+
// give the kernel a chance to finish closing the executable handle
227+
std.os.windows.kernel32.Sleep(@as(u32, 1) << attempt >> 1);
228+
attempt += 1;
229+
continue;
230+
},
231+
else => |e| return e,
232+
};
233+
}

0 commit comments

Comments
 (0)