-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
When running in windows environment, using the NODERAWFS file system, the getcwd()
syscall fails with ENOENT. The same wasm file, when run under the WSL environment, works correctly.
This has been observed in versions 4.0.10 and 4.0.15.
The following log should provide all that is needed to reproduce the issue,
C:\Users\jesullivan\work\emscripten_getcwd_issue
> dir
Volume in drive C is System
Volume Serial Number is ****-****
Directory of C:\Users\jesullivan\work\emscripten_getcwd_issue
17/09/2025 12:24 <DIR> .
17/09/2025 11:58 <DIR> ..
17/09/2025 12:06 <DIR> emsdk
17/09/2025 11:31 524 main.c
1 File(s) 524 bytes
3 Dir(s) 81,624,453,120 bytes free
C:\Users\jesullivan\work\emscripten_getcwd_issue
> type main.c
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int
main()
{
char cwd[PATH_MAX + 1] = {'\0'};
char* result = getcwd(cwd, sizeof(cwd));
if(result == NULL)
{
printf("Result = NULL, errno = \"%s\".\n", strerror(errno));
if (cwd[0] !='\0')
{
printf("Buffer Contents modified: now \"%s\".\n", cwd);
}
}
else
{
printf("Cwd is \"%s\".\n", result);
}
return 0;
}
C:\Users\jesullivan\work\emscripten_getcwd_issue
> emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 4.0.15 (09f52557f0d48b65b8c724853ed8f4e8bf80e669)
clang version 22.0.0git (https:/github.com/llvm/llvm-project 3388d40684742e950b3c5d1d2dafe5a40695cfc1)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\bin
C:\Users\jesullivan\work\emscripten_getcwd_issue
> emcc main.c -o test-getcwd -s NODERAWFS=1 -v
"C:/Users/jesullivan/work/emscripten_getcwd_issue/emsdk/upstream/bin\clang.exe" -target wasm32-unknown-emscripten -fignore-exceptions -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr '--sysroot=C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot' -DEMSCRIPTEN -Xclang '-iwithsysroot/include\fakesdl' -Xclang '-iwithsysroot/include\compat' -v -c main.c -o 'C:\Users\JESULL~1\AppData\Local\Temp\emscripten_temp_0gdzc76r\main_0.o'
clang version 22.0.0git (https:/github.com/llvm/llvm-project 3388d40684742e950b3c5d1d2dafe5a40695cfc1)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\bin
(in-process)
"C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\bin\\clang.exe" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.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=C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue" -v "-fcoverage-compilation-dir=C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue" -resource-dir "C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\lib\\clang\\22" -D EMSCRIPTEN -isysroot "C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\emscripten\\cache\\sysroot" -internal-isystem "C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\lib\\clang\\22\\include" -internal-isystem "C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\emscripten\\cache\\sysroot/include/wasm32-emscripten" -internal-isystem "C:\\Users\\jesullivan\\work\\emscripten_getcwd_issue\\emsdk\\upstream\\emscripten\\cache\\sysroot/include" -ferror-limit 19 -fmessage-length=160 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics "-iwithsysroot/include\\fakesdl" "-iwithsysroot/include\\compat" -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o "C:\\Users\\JESULL~1\\AppData\\Local\\Temp\\emscripten_temp_0gdzc76r\\main_0.o" -x c main.c
clang -cc1 version 22.0.0git based upon LLVM 22.0.0git default target x86_64-pc-windows-msvc
ignoring nonexistent directory "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot/include\fakesdl
C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot/include\compat
C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\lib\clang\22\include
C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot/include
End of search list.
"C:/Users/jesullivan/work/emscripten_getcwd_issue/emsdk/upstream/bin\clang.exe" --version
"C:/Users/jesullivan/work/emscripten_getcwd_issue/emsdk/upstream/bin\wasm-ld.exe" -o test-getcwd.wasm 'C:\Users\JESULL~1\AppData\Local\Temp\emscripten_temp_0gdzc76r\main_0.o' '-LC:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten' '-LC:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\src\lib' -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc-debug -lcompiler_rt -lc++-debug-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr 'C:\Users\JESULL~1\AppData\Local\Temp\tmp8e1scqk4libemscripten_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=__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
"C:/Users/jesullivan/work/emscripten_getcwd_issue/emsdk/upstream/bin\llvm-objcopy.exe" test-getcwd.wasm test-getcwd.wasm '--remove-section=.debug*' --remove-section=producers --remove-section=name
"C:/Users/jesullivan/work/emscripten_getcwd_issue/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\tools\compiler.mjs' -
C:\Users\jesullivan\work\emscripten_getcwd_issue
> node test-getcwd
Result = NULL, errno = "No such file or directory".
Buffer Contents modified: now "C:\Users\jesullivan\work\emscripten_getcwd_issue".
C:\Users\jesullivan\work\emscripten_getcwd_issue
> wsl
jeff@JESULLIVAN1L:/mnt/c/Users/jesullivan/work/emscripten_getcwd_issue$ node test-getcwd
Cwd is "/mnt/c/Users/jesullivan/work/emscripten_getcwd_issue".
jeff@JESULLIVAN1L:/mnt/c/Users/jesullivan/work/emscripten_getcwd_issue$
A quick investigation led me to emsdk/upstream/emscripten/system/lib/libc/musl/src/unistd/getcwd.c
which is
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "syscall.h"
char *getcwd(char *buf, size_t size)
{
char tmp[buf ? 1 : PATH_MAX];
if (!buf) {
buf = tmp;
size = sizeof tmp;
} else if (!size) {
errno = EINVAL;
return 0;
}
long ret = syscall(SYS_getcwd, buf, size);
if (ret < 0)
return 0;
if (ret == 0 || buf[0] != '/') {
errno = ENOENT;
return 0;
}
return buf == tmp ? strdup(buf) : buf;
}
Note the check for the initial character of the path returned from syscall(...)
being '/'. This is obviously not going to work well when the current working directory is "C:\Users\jesullivan\work\emscripten_getcwd_issue".
As a test I removed that test, cleared the cache and rebuild the library.
C:\Users\jesullivan\work\emscripten_getcwd_issue
> type emsdk\upstream\emscripten\system\lib\libc\musl\src\unistd\getcwd.c
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "syscall.h"
char *getcwd(char *buf, size_t size)
{
char tmp[buf ? 1 : PATH_MAX];
if (!buf) {
buf = tmp;
size = sizeof tmp;
} else if (!size) {
errno = EINVAL;
return 0;
}
long ret = syscall(SYS_getcwd, buf, size);
if (ret < 0)
return 0;
if (ret == 0 ) {
errno = ENOENT;
return 0;
}
return buf == tmp ? strdup(buf) : buf;
}
C:\Users\jesullivan\work\emscripten_getcwd_issue
> rm -rf emsdk\upstream\emscripten\cache\
C:\Users\jesullivan\work\emscripten_getcwd_issue
> emcc -g main.c -o test-getcwd -s NODERAWFS=1
shared:INFO: (Emscripten: Running sanity checks)
cache:INFO: generating system headers: sysroot_install.stamp... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot_install.stamp" for subsequent builds)
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libGL-getprocaddr.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libGL-getprocaddr.a" for subsequent builds)
system_libs:INFO: compiled 4 inputs in 0.46s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libal.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libal.a" for subsequent builds)
system_libs:INFO: compiled 1 inputs in 0.37s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libhtml5.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libhtml5.a" for subsequent builds)
system_libs:INFO: compiled 5 inputs in 0.48s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libstubs-debug.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libstubs-debug.a" for subsequent builds)
system_libs:INFO: compiled 2 inputs in 0.39s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libnoexit.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libnoexit.a" for subsequent builds)
system_libs:INFO: compiled 1 inputs in 0.34s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libc-debug.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libc-debug.a" for subsequent builds)
system_libs:INFO: compiled 1045 inputs in 23.88s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libdlmalloc-debug.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libdlmalloc-debug.a" for subsequent builds)
system_libs:INFO: compiled 2 inputs in 0.86s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libcompiler_rt.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libcompiler_rt.a" for subsequent builds)
system_libs:INFO: compiled 182 inputs in 6.61s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libc++-debug-noexcept.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libc++-debug-noexcept.a" for subsequent builds)
system_libs:INFO: compiled 56 inputs in 12.44s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libc++abi-debug-noexcept.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libc++abi-debug-noexcept.a" for subsequent builds)
system_libs:INFO: compiled 16 inputs in 3.32s
cache:INFO: - ok
cache:INFO: generating system library: sysroot\lib\wasm32-emscripten\libsockets.a... (this will be cached in "C:\Users\jesullivan\work\emscripten_getcwd_issue\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\libsockets.a" for subsequent builds)
system_libs:INFO: compiled 27 inputs in 2.20s
cache:INFO: - ok
C:\Users\jesullivan\work\emscripten_getcwd_issue
> node test-getcwd
Cwd is "C:\Users\jesullivan\work\emscripten_getcwd_issue".
C:\Users\jesullivan\work\emscripten_getcwd_issue
>
So that would seem to prove that the issue is in emsdk\upstream\emscripten\system\lib\libc\musl\src\unistd\getcwd.c
. This proof of the cause of the issue does not look like a robust fix: for that I might expect at least a check for valid drive letters and a colon, in addition to the check for '/'.