emscripten-core / emscripten-core/emscripten
getcwd() using NODERAWFS fails when node is running on a windows host.
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
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 .
17/09/2025 11:58 ..
17/09/2025 12:06 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
#include
#include
#include
#include
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
#include
#include
#include
#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
#include
#include
#include
#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 '/'.
Contributor guide
Assessment
This issue has not been assessed yet.