Skip to content

Linking against noderawfs.js causes ioctl_tiocgwinsz to fail #22264

@gudzpoz

Description

@gudzpoz

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61-git (67fa4c16496b157a7fc3377afd69ee0445e8a6e3)
clang version 19.0.0git (/startdir/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /opt/emscripten-llvm/bin

Reproducing steps

  1. Source file content:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ioctl.h>
    #include <err.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <termios.h>
    
    void ensure_noderawfs_init() {
        int c;
        FILE *file;
        file = fopen("/etc/hostname", "r");
        if (file) {
            while ((c = getc(file)) != EOF)
                putchar(c);
            fclose(file);
        }
    }
    
    void print_tty_size() {
        struct winsize ws;
        if(ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) { // <--------------------
            err(EXIT_FAILURE, "/dev/stdin not a tty");
        }
        printf("TTY Size: %d x %d\n", ws.ws_row, ws.ws_col);
    }
    
    int main() {
        ensure_noderawfs_init();
        print_tty_size();
        return 0;
    }
  2. Compile the code above and run it with node:

    $ emcc ioctl_test.c -lnodefs.js -lnoderawfs.js
    $ node ./a.out.js                      
    my-host-name      
    .../ledger/build/a.out.js:128
          throw ex;
          ^
    TypeError: Cannot read properties of undefined (reading 'ioctl_tiocgwinsz')
        at ___syscall_ioctl (.../ledger/build/a.out.js:4396:30)
       ...

Failing command line in full:

$ node ./a.out.js
my-host-name
.../ledger/build/a.out.js:128
      throw ex;
      ^

TypeError: Cannot read properties of undefined (reading 'ioctl_tiocgwinsz')
    at ___syscall_ioctl (.../ledger/build/a.out.js:4396:30)
    at wasm://wasm/0001a2fa:wasm-function[48]:0x13c2
    at wasm://wasm/0001a2fa:wasm-function[13]:0x4af
    at wasm://wasm/0001a2fa:wasm-function[14]:0x560
    at wasm://wasm/0001a2fa:wasm-function[15]:0x57d
    at .../ledger/build/a.out.js:641:12
    at callMain (.../ledger/build/a.out.js:4985:15)
    at doRun (.../ledger/build/a.out.js:5035:23)
    at run (.../ledger/build/a.out.js:5050:5)
    at runCaller (.../ledger/build/a.out.js:4970:19)

Node.js v20.12.2

Reproducing steps have been attached above.

Full link command and output with -v appended:

$ emcc ioctl_test.c -lnodefs.js -lnoderawfs.js -v
emcc ioctl_test.c -lnodefs.js -lnoderawfs.js -v 2>&1 | sed 's#/home/otaku/Workspaces/clones#...#g' | sed 's#/home/otaku/#$HOME/#g'
 /opt/emscripten-llvm/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=$HOME/.emscripten_cache/sysroot -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v ioctl_test.c -c -o /tmp/emscripten_temp_e8xdm84r/ioctl_test_0.o
clang version 19.0.0git (/startdir/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /opt/emscripten-llvm/bin
 (in-process)
 "/opt/emscripten-llvm/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ioctl_test.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -fdebug-compilation-dir=.../ledger/build -v -fcoverage-compilation-dir=.../ledger/build -resource-dir /opt/emscripten-llvm/lib/clang/19 -D EMSCRIPTEN -isysroot $HOME/.emscripten_cache/sysroot -internal-isystem /opt/emscripten-llvm/lib/clang/19/include -internal-isystem $HOME/.emscripten_cache/sysroot/include/wasm32-emscripten -internal-isystem $HOME/.emscripten_cache/sysroot/include -Werror=implicit-function-declaration -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_e8xdm84r/ioctl_test_0.o -x c ioctl_test.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "$HOME/.emscripten_cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 $HOME/.emscripten_cache/sysroot/include/fakesdl
 $HOME/.emscripten_cache/sysroot/include/compat
 /opt/emscripten-llvm/lib/clang/19/include
 $HOME/.emscripten_cache/sysroot/include
End of search list.
 /opt/emscripten-llvm/bin/clang --version
 /opt/emscripten-llvm/bin/wasm-ld -o a.out.wasm /tmp/emscripten_temp_e8xdm84r/ioctl_test_0.o -L$HOME/.emscripten_cache/sysroot/lib/wasm32-emscripten -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmpa_r6uqttlibemscripten_js_symbols.so --strip-debug --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=_emscripten_stack_alloc --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export=_emscripten_stack_restore --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --no-growable-memory --initial-heap=16777216 --no-entry --stack-first --table-base=1
 /opt/emscripten-llvm/bin/llvm-objcopy a.out.wasm a.out.wasm --remove-section=.debug* --remove-section=producers
 /usr/bin/wasm-emscripten-finalize --dyncalls-i64 --pass-arg=legalize-js-interface-exported-helpers a.out.wasm -o a.out.wasm --detect-features
 /usr/bin/node /usr/lib/emscripten/src/compiler.mjs /tmp/tmpek0bu9lr.json

Extra info

It seems to come from library_noderawfs.js setting stream.tty to true, while ioctl implementation in library_syscall.js expects a TTY object:

createStandardStreams() {
FS.createStream({ nfd: 0, position: 0, path: '', flags: 0, tty: true, seekable: false }, 0);
for (var i = 1; i < 3; i++) {
FS.createStream({ nfd: i, position: 0, path: '', flags: 577, tty: true, seekable: false }, i);
}
},

if (!stream.tty) return -{{{ cDefs.ENOTTY }}};
if (stream.tty.ops.ioctl_tiocgwinsz) {
var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
var argp = syscallGetVarargP();
{{{ makeSetValue('argp', 0, 'winsize[0]', 'i16') }}};
{{{ makeSetValue('argp', 2, 'winsize[1]', 'i16') }}};
}

But I couldn't find any documentation on that tty field though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions