Skip to content

posix.fstatat fails to propogate SYMLINK_NOFOLLOW when linking wasi-libc #20890

Closed
@squeek502

Description

@squeek502

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:

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.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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behavioros-wasistandard libraryThis issue involves writing Zig code for the standard library.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions