ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.47k stars 2.52k forks source link

"error: failed to rename compilation results" when using `zig build test --watch` on Windows #21104

Open kcbanner opened 2 months ago

kcbanner commented 2 months ago

Zig Version

0.14.0-dev.1077+9be10ea96

Steps to Reproduce and Observed Behavior

  1. zig init
  2. zig build test --watch
  3. Edit src/main.zig, comment line 24 (so the test fails)
  4. The watcher rebuilds it and the test fails
  5. Uncomment the line

Repeat steps 3-5 until the crash is observed - this takes around 3 tries for me (there must be a race condition somewhere in this logic):

error: failed to rename compilation results ('c:\cygwin64\home\kcbanner\temp\watch\.zig-cache\tmp\44b0a3ebbd5749a5') into local cache ('c:\cygwin64\home\kcbanner\temp\watch\.zig-cache\o\e5978ca4b34c31e02cb598792a99289d'): AccessDenied
error: the following command failed with 1 compilation errors:
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\bin\zig.exe test -ODebug -Mroot=C:\cygwin64\home\kcbanner\temp\watch\src\main.zig --cache-dir c:\cygwin64\home\kcbanner\temp\watch\.zig-cache --global-cache-dir e:\dev\zig-cache --name test --zig-lib-dir C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\ --listen=-
Build Summary: 2/5 steps succeeded; 1 failed; 1/1 tests passed
test transitive failure
└─ run test transitive failure
   └─ zig test Debug native 1 errors
error.Unexpected: GetLastError(5): Access is denied.

C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:285:69: 0x2fa4b8 in startListening (build.exe.obj)
                        else => |err| return windows.unexpectedError(err),
                                                                    ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:425:35: 0x300d9e in markDirtySteps (build.exe.obj)
            try dir.startListening();
                                  ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:667:52: 0x301851 in wait (build.exe.obj)
                    break if (try Os.markDirtySteps(w, gpa, dir))
                                                   ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\compiler\build_runner.zig:464:40: 0x306abf in main (build.exe.obj)
        while (true) switch (try w.wait(gpa, debounce_timeout)) {
                                       ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\start.zig:442:53: 0x30cfd7 in WinStartup (build.exe.obj)
    std.os.windows.ntdll.RtlExitUserProcess(callMain());
                                                    ^
???:?:?: 0x7ffdd2187373 in ??? (KERNEL32.DLL)
???:?:?: 0x7ffdd309cc90 in ??? (ntdll.dll)
error: Unexpected
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\os\windows.zig:2789:5: 0x2fa5bc in unexpectedError (build.exe.obj)
    return error.Unexpected;
    ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:285:39: 0x2fa4c5 in startListening (build.exe.obj)
                        else => |err| return windows.unexpectedError(err),
                                      ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:425:13: 0x3011bc in markDirtySteps (build.exe.obj)
            try dir.startListening();
            ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\std\Build\Watch.zig:667:31: 0x301892 in wait (build.exe.obj)
                    break if (try Os.markDirtySteps(w, gpa, dir))
                              ^
C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig\compiler\build_runner.zig:464:30: 0x306b08 in main (build.exe.obj)
        while (true) switch (try w.wait(gpa, debounce_timeout)) {
                             ^
error: the following build command failed with exit code 1:
c:\cygwin64\home\kcbanner\temp\watch\.zig-cache\o\2a5397fa816ba930eaa2dcbaa4a553c9\build.exe C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\bin\zig.exe C:\cygwin64\home\kcbanner\kit\zig\build-stage3-release\lib\zig c:\cygwin64\home\kcbanner\temp\watch c:\cygwin64\home\kcbanner\temp\watch\.zig-cache e:\dev\zig-cache --seed 0x4e66927e -Zc3905d7c88a20ee8 test --watch

Expected Behavior

The watcher should remain alive without crashing.

squeek502 commented 2 months ago

cc @jayrod246 (the version in the OP includes https://github.com/ziglang/zig/pull/20907 btw)

jayrod246 commented 2 months ago

I placed this code at line 466 in Watch.zig:

for (files.items) |basename| {
    const tmp = try path.joinString(gpa, basename);
    defer gpa.free(tmp);
    path.access(basename, .{}) catch {
        std.debug.print("\n*****************\nFILE MISSING: {s}\n*****************\n", .{tmp});
    };
    const gop = try reaction_set.getOrPut(gpa, basename);
    if (!gop.found_existing) gop.value_ptr.* = .{};
    try gop.value_ptr.put(gpa, step, w.generation);
}

and repeating your steps I eventually get:

*****************
FILE MISSING: C:\Dev\watch-test\.zig-cache\o\356a82588c29f2bf10b5221a7f14b907\test.exe
*****************

At this point, the file test.exe which is an input to some step, gets marked as "persisted". But since that file doesn’t exist, and from what I could tell the parent directory no longer exists either, we get the access denied. I want to guess that the problem stems from somewhere else in the build system? (the input files comes from a Step’s inputs, which are passed in from outside Watch.zig)

jayrod246 commented 2 months ago

This might have more to do with #20631 as I noticed we are attempting to watch directories inside .zig-cache/o/.

test.exe is an artifact, which Watch.zig is attempting to track. But the Run step that depends on the artifact should have been invalidated already by the source files from which the artifact is built.

The solution I suppose is to avoid watching artifact directories, which in turn should avoid the AccessDenied error. (which I assume is caused by the Watch.zig file handle we have open on it)

kcbanner commented 2 months ago

Interesting, yea that does seem to be the cause. Thanks for looking into this!