authorgravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2025-07-19 09:34:04-07:00
committergravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2025-08-06 22:12:42-07:00
logcf47d283d101e5d8e0d1ca7ec427d40efc40f358
tree96494f4cd5859c4ba30d375552912c4445f9a2ab
parentcaf80e90b85a2a7855c369887dce163cf036ff7e

lib/std/posix/test.zig: don't compare blksize in "fstatat"

In trying to reproduce the race in #24380, my system tripped over the stat "blocks" field changing in this test. The value was almost always 8 (effectively 4k) or very infrequently 0 (I saw the 0 from both `fstat` and `fstatat`). I believe the underlying filesystem is free to asynchronously change this value. For example, if it migrates a file between some "inline" or maybe journal storage, and actual on-disk blocks. So it seems plausible that its allowed to change between stat calls. Breaking up the struct comparison this way means we also don't compare any of the padding or "reserved" fields, too. And we can narrow down the s390x-linux work-around.

1 files changed, 21 insertions(+), 5 deletions(-)

lib/std/posix/test.zig+21-5
...@@ -395,11 +395,27 @@ test "fstatat" {...@@ -395,11 +395,27 @@ test "fstatat" {
395 // now repeat but using `fstatat` instead395 // now repeat but using `fstatat` instead
396 const statat = try posix.fstatat(tmp.dir.fd, "file.txt", posix.AT.SYMLINK_NOFOLLOW);396 const statat = try posix.fstatat(tmp.dir.fd, "file.txt", posix.AT.SYMLINK_NOFOLLOW);
397397
398 // s390x-linux does not have nanosecond precision for fstat(), but it does for fstatat(). As a398 try expectEqual(stat.dev, statat.dev);
399 // result, comparing the two structures is doomed to fail.399 try expectEqual(stat.ino, statat.ino);
400 if (builtin.cpu.arch == .s390x and builtin.os.tag == .linux) return error.SkipZigTest;400 try expectEqual(stat.nlink, statat.nlink);
401401 try expectEqual(stat.mode, statat.mode);
402 try expectEqual(stat, statat);402 try expectEqual(stat.uid, statat.uid);
403 try expectEqual(stat.gid, statat.gid);
404 try expectEqual(stat.rdev, statat.rdev);
405 try expectEqual(stat.size, statat.size);
406 try expectEqual(stat.blksize, statat.blksize);
407
408 // The stat.blocks/statat.blocks count is managed by the filesystem and may
409 // change if the file is stored in a journal or "inline".
410 // try expectEqual(stat.blocks, statat.blocks);
411
412 // s390x-linux does not have nanosecond precision for fstat(), but it does for
413 // fstatat(). As a result, comparing the timestamps isn't worth the effort
414 if (!(builtin.cpu.arch == .s390x and builtin.os.tag == .linux)) {
415 try expectEqual(stat.atime(), statat.atime());
416 try expectEqual(stat.mtime(), statat.mtime());
417 try expectEqual(stat.ctime(), statat.ctime());
418 }
403}419}
404420
405test "readlinkat" {421test "readlinkat" {