def test_libc_ver(self):
if support.is_emscripten:
- assert platform.libc_ver() == ("emscripten", "4.0.19")
+ import tomllib
+ from pathlib import Path
+
+ # Get expected emscripten version from emscripten config
+ config_path = (
+ Path(__file__).parents[2] / "Platforms/emscripten/config.toml"
+ )
+ with open(config_path, "rb") as fp:
+ emscripten_version = tomllib.load(fp)["emscripten-version"]
+
+ self.assertEqual(
+ platform.libc_ver(), ("emscripten", emscripten_version)
+ )
+
return
# check that libc_ver(executable) doesn't raise an exception
if os.path.isdir(sys.executable) and \
return __syscall_getuid32_js();
}
-EM_JS(int, __syscall_umask_js, (int mask), {
- // If we're in node and we can, call native process.umask()
+// Emscripten's syscall layer tracks the umask in SYSCALLS.currentUmask and
+// applies it itself when creating files and directories. We mount the real
+// filesystem via NODEFS, which applies proces.umask() to everything as well. To
+// avoid masking the mode twice, read and zero out process umask at startup,
+// and store it as emscripten's umask.
+EM_JS(void, __syscall_init_umask_js, (void), {
if (ENVIRONMENT_IS_NODE) {
try {
- return process.umask(mask);
- } catch(e) {
- // oops...
- // NodeJS docs: "In Worker threads, process.umask(mask) will throw an exception."
- // umask docs: "This system call always succeeds"
- return 0;
+ // process.umask(0) returns the previous umask and sets it to 0.
+ SYSCALLS.currentUmask = process.umask(0);
+ } catch (e) {
+ // NodeJS docs: "In Worker threads, process.umask(mask) will throw an
+ // exception." In that case just keep emscripten's default umask.
}
}
- // Fall back to the stub case of returning 0.
- return 0;
})
-int __syscall_umask(int mask) {
- return __syscall_umask_js(mask);
+EM_JS_DEPS(__syscall_init_umask, "$SYSCALLS");
+
+__attribute__((constructor)) void __syscall_init_umask(void) {
+ __syscall_init_umask_js();
}
#include <wasi/api.h>
return __block_for_int(p);
}
+
+// Workaround for an Emscripten bug: getentropy(buffer, 1) returns the single
+// byte of entropy as the return code. Fixed upstream by
+// emscripten-core/emscripten#27122
+int __real_getentropy(void*, size_t);
+
+int __wrap_getentropy(void *buffer, size_t len) {
+ if (len != 1) {
+ return __real_getentropy(buffer, len);
+ }
+ // Length is 1. Workaround is to get two bytes of entropy and write the
+ // first one into the original target buffer.
+ uint8_t tmp[2];
+ int ret = __real_getentropy(tmp, 2);
+ if (ret == 0) {
+ *(uint8_t *)buffer = tmp[0];
+ }
+ return ret;
+}
+
#include <sys/ioctl.h>
int syscall_ioctl_orig(int fd, int request, void* varargs)
dnl Avoid bugs in JS fallback string decoding path
AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"])
+ dnl Workaround for a bug in Emscipten libc's getentropy. See
+ dnl __wrap_getentropy in Python/emscripten_syscalls.c.
+ AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--wrap=getentropy"])
+
AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [
AS_VAR_APPEND([LINKFORSHARED], [" -sMAIN_MODULE"])
])