ziglang / zig

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

flaky fs test: `Dir.rename directories` on aarch64-windows #17134

Open squeek502 opened 10 months ago

squeek502 commented 10 months ago

Zig Version

0.12.0-dev.309+402468b21

Steps to Reproduce and Observed Behavior

Occasionally, the rename directories test in fs/test.zig will fail on the aarch64-windows CI with AccessDenied when trying to rename a directory (example CI run). The flaky test was introduced in https://github.com/ziglang/zig/pull/16847, some discussion of this bug can be found there too.

run test std-aarch64-windows-gnu-Debug-libc: error: 'test.Dir.rename directories' failed: AccessDenied, path type: unc
C:\actions-runner1\_work\zig\zig\lib\std\os.zig:2709:27: 0x7ff65b9fb87f in renameatW (test.exe.obj)
        .ACCESS_DENIED => return error.AccessDenied,
                          ^
C:\actions-runner1\_work\zig\zig\lib\std\os.zig:2531:9: 0x7ff65b7b05db in renameat (test.exe.obj)
        return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE);
        ^
C:\actions-runner1\_work\zig\zig\lib\std\fs.zig:1924:9: 0x7ff65b7c1b0b in rename (test.exe.obj)
        return os.renameat(self.fd, old_sub_path, self.fd, new_sub_path);
        ^
C:\actions-runner1\_work\zig\zig\lib\std\fs\test.zig:731:13: 0x7ff65b7c2687 in impl (test.exe.obj)
            try ctx.dir.rename(test_dir_renamed_path, test_dir_renamed_again_path);
            ^
C:\actions-runner1\_work\zig\zig\lib\std\fs\test.zig:121:13: 0x7ff65b7c2b87 in testWithAllSupportedPathTypes__anon_96449 (test.exe.obj)
            return err;
            ^
C:\actions-runner1\_work\zig\zig\lib\std\fs\test.zig:712:5: 0x7ff65b7c2f4b in test.Dir.rename directories (test.exe.obj)
    try testWithAllSupportedPathTypes(struct {
    ^

This is reproducible on x86_64 Windows, too, but it has never failed in that CI environment.

Some necessary conditions for reproduction that I could find:

Reproduction code (from @jacobly0 here); it should fail on some iteration (but which iteration it fails on is not consistent):

const std = @import("std");

pub fn main() !void {
    const root = "\\_";
    const cwd = std.fs.cwd();

    try cwd.deleteTree("C:" ++ root);
    try cwd.makeDir("C:" ++ root);
    defer cwd.deleteTree("C:" ++ root) catch |err| {
        std.debug.print("cwd.deleteTree(\"C:\" ++ root) = {}\n", .{err});
    };

    for (0..1000) |i| {
        const a_path = switch (@as(u1, @truncate(i))) {
            0 => "C:" ++ root ++ "\\a",
            1 => "\\\\127.0.0.1\\C$" ++ root ++ "\\a",
        };

        try cwd.makeDir(a_path);

        {
            var dir = try cwd.openDir(a_path, .{});
            defer dir.close();

            const file = try dir.createFile("f", .{ .read = true });
            defer file.close();
        }

        const b_path = switch (@as(u1, @truncate(i))) {
            0 => "C:" ++ root ++ "\\b",
            1 => "\\\\127.0.0.1\\C$" ++ root ++ "\\b",
        };
        cwd.rename(a_path, b_path) catch |err| {
            std.debug.print("{}: cwd.rename(\"{}\", \"{}\") = {}\n", .{
                i,
                std.zig.fmtEscapes(a_path),
                std.zig.fmtEscapes(b_path),
                err,
            });
            var d = try cwd.openIterableDir("C:" ++ root, .{});
            defer d.close();
            var w = try d.walk(std.heap.page_allocator);
            defer w.deinit();
            while (try w.next()) |e| std.debug.print("{s}\n", .{e.path});
            return err;
        };

        {
            var dir = try cwd.openDir(b_path, .{});
            defer dir.close();

            try dir.deleteFile("f");
        }
        try cwd.deleteDir(b_path);
    }
}

Expected Behavior

No intermittent AccessDenied errors

squeek502 commented 10 months ago

Seem to have hit this in the Dir.rename files test here: https://github.com/ziglang/zig/actions/runs/6173023767/job/16763286854?pr=17143

I'm unable to reproduce this one, though. With all the conditions in the OP, I am still able to run that test case tens of thousands of times successfully.

Weirdly, too, the trace seems to point to the rename of the file when it's expecting FileNotFound:

C:\actions-runner\_work\zig\zig\lib\std\fs\test.zig:681:36: 0x7ff7b7bc485f in impl (test.exe.obj)
            try testing.expectError(error.FileNotFound, ctx.dir.rename(missing_file_path, something_else_path));

which makes very little sense to me. Even stranger, if that rename is returning AccessDenied then the test should be failing with TestUnexpectedError, not AccessDenied, so the stack trace might be wrong in this case?

mlugg commented 2 months ago

Seems to also be flaky on x86_64-windows: https://github.com/ziglang/zig/actions/runs/8759547226/job/24042803455

mlugg commented 2 months ago

Never mind -- @jacobly0 let me know that this was just a configuration mistake on the CI runner. PR closed.