-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
| switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) { |
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.wasmAnd 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