]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-145177: Bump Emscripten to 6.0.0 (#151611)
authorHood Chatham <roberthoodchatham@gmail.com>
Thu, 18 Jun 2026 23:29:33 +0000 (19:29 -0400)
committerGitHub <noreply@github.com>
Thu, 18 Jun 2026 23:29:33 +0000 (07:29 +0800)
Bumps Emscripten to 6.0.0, and fixes related issues in getentropy() and umask().

Lib/test/test_platform.py
Platforms/emscripten/config.toml
Python/emscripten_syscalls.c
configure
configure.ac

index 63c130813ec4972471fab791c2bc54d69670e9f1..3503eaefaf8e9e76eebea82f3f8ece5021aba774 100644 (file)
@@ -534,7 +534,20 @@ class PlatformTest(unittest.TestCase):
 
     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 \
index 401e9396ddbb00943535b2164bef1ae033190f6d..389d2ea66ce948e13d06f4fa7a77dd912560a082 100644 (file)
@@ -1,7 +1,7 @@
 # Any data that can vary between Python versions is to be kept in this file.
 # This allows for blanket copying of the Emscripten build code between supported
 # Python versions.
-emscripten-version = "4.0.19"
+emscripten-version = "6.0.0"
 node-version = "24"
 test-args = [
     "-m", "test",
index 98ee44276e53e03503adea3cc2d1be63cbd2b6ed..b0c370ced36cc3335b1703373fce816c49b26948 100644 (file)
@@ -23,24 +23,27 @@ int __syscall_getuid32(void) {
     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>
@@ -290,6 +293,26 @@ int __syscall_poll(intptr_t fds, int nfds, int timeout) {
     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)
index 7408fac738b8a398e6d334eea30ed012d9169c70..d73a88d04016ddb43329788b802d3f2d90e98132 100755 (executable)
--- a/configure
+++ b/configure
@@ -9803,6 +9803,8 @@ fi
     as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB"
         as_fn_append LINKFORSHARED " -sTEXTDECODER=2"
 
+            as_fn_append LDFLAGS_NODIST " -Wl,--wrap=getentropy"
+
     if test "x$enable_wasm_dynamic_linking" = xyes
 then :
 
index dbc781b545dd362d342ea7a88ef4fefc8db68b2e..8ba134c77b341299ef611c25e165a1001eeaa99b 100644 (file)
@@ -2411,6 +2411,10 @@ AS_CASE([$ac_sys_system],
     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"])
     ])