Description
Zig Version
0.14.0-dev.653+91c17979f
Steps to Reproduce and Observed Behavior
const std = @import("std");
test "fstatat on a symlink with SYMLINK_NOFOLLOW" {
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const testfile = try tmp.dir.createFile("testfile", .{});
testfile.close();
try tmp.dir.symLink("testfile", "testsymlink", .{});
const stat = try std.posix.fstatat(tmp.dir.fd, "testsymlink", std.posix.AT.SYMLINK_NOFOLLOW);
std.testing.expect(stat.mode & std.posix.S.IFLNK == std.posix.S.IFLNK) catch |err| {
std.debug.print("stat.mode={X}\n", .{stat.mode});
return err;
};
}
This test passes normally and when targeting wasm32-wasi
and not linking libc:
$ zig test stat-symlink-test.zig -target wasm32-wasi -femit-bin=stat-symlink-test.wasm --test-no-exec
$ wasmtime --dir=. stat-symlink-test.wasm
All 1 tests passed.
But fails when linking libc (meaning wasi-libc
):
$ wasmtime --dir=. stat-symlink-test-libc.wasm
stat.mode=8000
1/1 stat-symlink-test.test.fstatat on a symlink with SYMLINK_NOFOLLOW...FAIL (TestUnexpectedResult)
Unable to dump stack trace: not implemented for Wasm
0 passed; 0 skipped; 1 failed.
(that mode is IFREG
aka a file)
This is not a problem with the parameters being passed to fstatat
: I confirmed that the AT_SYMLINK_NOFOLLOW
is being passed to the fstatat_sym
call here:
Line 4382 in 059856a
But strace
shows that the NOFOLLOW
flag is being dropped when going through wasmtime
(the openat2
call should have O_NOFOLLOW
, which it does when not linking wasi-libc
):
openat2(13, "testsymlink", {flags=O_RDONLY|O_CLOEXEC|O_PATH, resolve=RESOLVE_NO_MAGICLINKS|RESOLVE_BENEATH}, 24) = 11
statx(11, "", AT_STATX_SYNC_AS_STAT|AT_EMPTY_PATH, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0664, stx_size=0, ...}) = 0
close(11) = 0
My first thought was that this is a wasi-libc
/wasmtime
bug, similar to #20747, but I have been unable to find a reproduction when building an intended-to-be-equivalent C version via wasi-sdk
. Here's the program I'm trying (I'm using wasi-sdk 23.0
and wasmtime 23.0.1
):
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
mkdirat(AT_FDCWD, "testdir", 0777);
int dirfd = openat(AT_FDCWD, "testdir", O_RDONLY|O_DIRECTORY);
int fd = openat(dirfd, "testfile", O_RDONLY|O_CREAT);
close(fd);
symlinkat("testfile", dirfd, "testsymlink");
struct stat st;
fstatat(dirfd, "testsymlink", &st, AT_SYMLINK_NOFOLLOW);
printf("%X\n", st.st_mode);
if ((st.st_mode & S_IFLNK) == 0) return 1;
return 0;
}
Built with:
$ WASI_SDK=/home/ryan/Downloads/wasi-sdk-23.0-x86_64-linux
$ $WASI_SDK/bin/clang --sysroot=$WASI_SDK/share/wasi-sysroot stat-symlink.c -o stat-symlink-sdk.wasm
And run with:
$ wasmtime --dir=. stat-symlink-sdk.wasm
A000
(0xA000 is S_IFLNK aka symlink)
Expected Behavior
The test to pass when linking wasi-libc