From c9d9de9d54286c1f95267e05da2bf48b3779894b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 23 Mar 2026 16:41:00 -0700 Subject: [PATCH] [AUDIO_WORKLET] Fix getentropy when called from an audio worklet. Fixes: #26522, #13224 --- src/lib/libwasi.js | 23 +++--- system/lib/libc/musl/src/misc/getentropy.c | 6 +- test/codesize/audio_worklet_wasm.expected.js | 78 ++++++++++--------- test/codesize/test_codesize_cxx_ctors1.json | 8 +- test/codesize/test_codesize_cxx_ctors2.json | 8 +- test/codesize/test_codesize_cxx_except.json | 8 +- .../test_codesize_cxx_except_wasm.json | 4 +- .../test_codesize_cxx_except_wasm_legacy.json | 8 +- test/codesize/test_codesize_cxx_lto.json | 8 +- test/codesize/test_codesize_cxx_mangle.json | 8 +- test/codesize/test_codesize_cxx_noexcept.json | 8 +- test/codesize/test_codesize_cxx_wasmfs.json | 12 +-- .../test_codesize_file_preload.expected.js | 7 +- test/codesize/test_codesize_file_preload.json | 8 +- test/codesize/test_codesize_files_js_fs.json | 8 +- test/codesize/test_codesize_files_wasmfs.json | 10 +-- test/codesize/test_codesize_hello_dylink.json | 8 +- .../test_codesize_hello_dylink_all.json | 6 +- ...nimal_runtime_code_size_audio_worklet.json | 12 +-- test/webaudio/audioworklet.c | 21 ++++- 20 files changed, 138 insertions(+), 121 deletions(-) diff --git a/src/lib/libwasi.js b/src/lib/libwasi.js index bb67581f269a6..2b18322bdd802 100644 --- a/src/lib/libwasi.js +++ b/src/lib/libwasi.js @@ -593,27 +593,30 @@ var WasiLibrary = { } #endif +#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET + // Audio worklets don't support crypto.getRandomValues + if (ENVIRONMENT_IS_AUDIO_WORKLET) { //!globalThis.crypto) { + return () => {{{ cDefs.ENOTSUP }}}; + } +#endif + #if SHARED_MEMORY // like with most Web APIs, we can't use Web Crypto API directly on shared memory, // so we need to create an intermediate buffer and copy it to the destination - return (view) => view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))); + return (view) => (view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))), 0); #else - return (view) => crypto.getRandomValues(view); + return (view) => (crypto.getRandomValues(view), 0); #endif }, $randomFill__deps: ['$initRandomFill'], - $randomFill: (view) => { - // Lazily init on the first invocation. - (randomFill = initRandomFill())(view); - }, + // Lazily init on the first invocation. + $randomFill: (view) => (randomFill = initRandomFill())(view), random_get__proxy: 'none', + random_get__nothrow: true, random_get__deps: ['$randomFill'], - random_get: (buffer, size) => { - randomFill(HEAPU8.subarray(buffer, buffer + size)); - return 0; - }, + random_get: (buffer, size) => randomFill(HEAPU8.subarray(buffer, buffer + size)), }; for (var x in WasiLibrary) { diff --git a/system/lib/libc/musl/src/misc/getentropy.c b/system/lib/libc/musl/src/misc/getentropy.c index f5204186fca42..c42689f427530 100644 --- a/system/lib/libc/musl/src/misc/getentropy.c +++ b/system/lib/libc/musl/src/misc/getentropy.c @@ -18,11 +18,11 @@ int getentropy(void *buffer, size_t len) return -1; } - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); - #ifdef __EMSCRIPTEN__ ret = __wasi_syscall_ret(__wasi_random_get(buffer, len)); #else + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + while (len) { ret = getrandom(pos, len, 0); if (ret < 0) { @@ -33,9 +33,9 @@ int getentropy(void *buffer, size_t len) len -= ret; ret = 0; } -#endif pthread_setcancelstate(cs, 0); +#endif return ret; } diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index 643915035b33c..33b2b8c2790ac 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -42,9 +42,9 @@ if (p) { var H = 0; for (f of g) H += f.length; n += H * this.s; - var N = 0; - for (f in e) ++N, k += 8, n += e[f].byteLength; - var U = C(), B = k + n + 15 & -16; + var O = 0; + for (f in e) ++O, k += 8, n += e[f].byteLength; + var V = C(), B = k + n + 15 & -16; k = D(B); n = k + (B - n); B = k; @@ -61,8 +61,8 @@ if (p) { e = k; for (f of g) G[k >> 2] = f.length, G[k + 4 >> 2] = this.u, G[k + 8 >> 2] = n, k += 12, n += this.s * f.length; - if (l = this.v(l, B, q, e, N, d, this.A)) for (f of g) for (r of f) r.set(this.B[--H]); - F(U); + if (l = this.v(l, B, q, e, O, d, this.A)) for (f of g) for (r of f) r.set(this.B[--H]); + F(V); return !!l; } } @@ -109,9 +109,9 @@ var K = [], L = a => { }, M = a => { K.push(a); }, P = (a, c, b, h) => { - c = O[c]; - O[a].connect(c.destination || c, b, h); -}, O = {}, Q = 0, R = globalThis.TextDecoder && new TextDecoder, S = (a = 0) => { + c = N[c]; + N[a].connect(c.destination || c, b, h); +}, N = {}, Q = 0, R = globalThis.TextDecoder && new TextDecoder, S = (a = 0) => { for (var c = I, b = a, h = b + void 0; c[b] && !(b >= h); ) ++b; if (16 < b - a && c.buffer && R) return R.decode(c.slice(a, b)); for (h = ""; a < b; ) { @@ -138,9 +138,9 @@ var K = [], L = a => { }; } else a = void 0; a = new AudioContext(a); - O[++Q] = a; + N[++Q] = a; return Q; -}, V = (a, c, b, h, d) => { +}, U = (a, c, b, h, d) => { var g = b ? J[b + 4 >> 2] : 0; if (b) { var e = J[b >> 2], l = G[b + 8 >> 2], q = g; @@ -159,14 +159,14 @@ var K = [], L = a => { processorOptions: { v: h, A: d, - u: O[a].renderQuantumSize || 128 + u: N[a].renderQuantumSize || 128 } }; } else b = void 0; - a = new AudioWorkletNode(O[a], c ? S(c) : "", b); - O[++Q] = a; + a = new AudioWorkletNode(N[a], c ? S(c) : "", b); + N[++Q] = a; return Q; -}, W = (a, c, b, h) => { +}, aa = (a, c, b, h) => { var d = (d = G[c >> 2]) ? S(d) : "", g = J[c + 4 >> 2]; c = G[c + 8 >> 2]; for (var e = [], l = 0; g--; ) e.push({ @@ -176,19 +176,19 @@ var K = [], L = a => { maxValue: E[c + 8 >> 2], automationRate: (J[c + 12 >> 2] ? "k" : "a") + "-rate" }), c += 16; - O[a].audioWorklet.port.postMessage({ + N[a].audioWorklet.port.postMessage({ _wpn: d, I: e, J: a, v: b, A: h }); -}, aa = () => !1, ba = 1, ca = a => { +}, ba = () => !1, ca = 1, da = a => { a = a.data; var c = a._wsc; c && A.get(c)(...a.C); -}, da = (a, c, b, h, d) => { - var g = O[a], e = g.audioWorklet, l = () => { +}, ea = (a, c, b, h, d) => { + var g = N[a], e = g.audioWorklet, l = () => { A.get(h)(a, 0, d); }; if (!e) return l(); @@ -204,22 +204,23 @@ var K = [], L = a => { }); e.port.postMessage({ _boot: 1, - M: ba++, + M: ca++, G: m.wasm, H: w, K: c, F: b }); - e.port.onmessage = ca; + e.port.onmessage = da; A.get(h)(a, 1, d); })).catch(l); -}; +}, fa = () => p ? () => 138 : a => (a.set(crypto.getRandomValues(new Uint8Array(a.byteLength))), +0), W = a => (W = fa())(a), ha = (a, c) => W(I.subarray(a, a + c)); -function ea(a) { +function ia(a) { let c = document.createElement("button"); c.innerHTML = "Toggle playback"; document.body.appendChild(c); - a = O[a]; + a = N[a]; c.onclick = () => { "running" != a.state ? a.resume() : a.suspend(); }; @@ -227,27 +228,28 @@ function ea(a) { function y() { Z = { - f: ea, - g: P, - d: T, - h: V, - e: W, - b: aa, - c: da, - a: w + g: ia, + h: P, + e: T, + i: U, + f: aa, + b: ba, + d: ea, + a: w, + c: ha }; z = WebAssembly.instantiate(m.wasm, { a: Z }).then((a => { a = (a.instance || a).exports; - X = a.j; - F = a.l; - D = a.m; - C = a.n; - Y = a.o; - A = a.k; + X = a.k; + F = a.m; + D = a.n; + C = a.o; + Y = a.p; + A = a.l; t ? (Y(u.M, u.K, u.F), p || (removeEventListener("message", M), K = K.forEach(L), - addEventListener("message", L))) : a.i(); + addEventListener("message", L))) : a.j(); t || X(); })); } diff --git a/test/codesize/test_codesize_cxx_ctors1.json b/test/codesize/test_codesize_cxx_ctors1.json index ada89930a22df..18689606b91f1 100644 --- a/test/codesize/test_codesize_cxx_ctors1.json +++ b/test/codesize/test_codesize_cxx_ctors1.json @@ -1,10 +1,10 @@ { - "a.out.js": 19193, - "a.out.js.gz": 7970, + "a.out.js": 19195, + "a.out.js.gz": 7973, "a.out.nodebug.wasm": 132638, "a.out.nodebug.wasm.gz": 49927, - "total": 151831, - "total_gz": 57897, + "total": 151833, + "total_gz": 57900, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_ctors2.json b/test/codesize/test_codesize_cxx_ctors2.json index 4bacbacb3ddd8..0352ce530c044 100644 --- a/test/codesize/test_codesize_cxx_ctors2.json +++ b/test/codesize/test_codesize_cxx_ctors2.json @@ -1,10 +1,10 @@ { - "a.out.js": 19170, - "a.out.js.gz": 7957, + "a.out.js": 19172, + "a.out.js.gz": 7960, "a.out.nodebug.wasm": 132064, "a.out.nodebug.wasm.gz": 49586, - "total": 151234, - "total_gz": 57543, + "total": 151236, + "total_gz": 57546, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_except.json b/test/codesize/test_codesize_cxx_except.json index 65d5840622ee1..435c47f5499e1 100644 --- a/test/codesize/test_codesize_cxx_except.json +++ b/test/codesize/test_codesize_cxx_except.json @@ -1,10 +1,10 @@ { - "a.out.js": 23173, - "a.out.js.gz": 8962, + "a.out.js": 23175, + "a.out.js.gz": 8964, "a.out.nodebug.wasm": 172516, "a.out.nodebug.wasm.gz": 57438, - "total": 195689, - "total_gz": 66400, + "total": 195691, + "total_gz": 66402, "sent": [ "__cxa_begin_catch", "__cxa_end_catch", diff --git a/test/codesize/test_codesize_cxx_except_wasm.json b/test/codesize/test_codesize_cxx_except_wasm.json index 5fc2a31081154..f71cc060337a5 100644 --- a/test/codesize/test_codesize_cxx_except_wasm.json +++ b/test/codesize/test_codesize_cxx_except_wasm.json @@ -1,9 +1,9 @@ { - "a.out.js": 19025, + "a.out.js": 19027, "a.out.js.gz": 7908, "a.out.nodebug.wasm": 147922, "a.out.nodebug.wasm.gz": 55312, - "total": 166947, + "total": 166949, "total_gz": 63220, "sent": [ "_abort_js", diff --git a/test/codesize/test_codesize_cxx_except_wasm_legacy.json b/test/codesize/test_codesize_cxx_except_wasm_legacy.json index 0b8f59eaf5ca2..b8b4d629e37bc 100644 --- a/test/codesize/test_codesize_cxx_except_wasm_legacy.json +++ b/test/codesize/test_codesize_cxx_except_wasm_legacy.json @@ -1,10 +1,10 @@ { - "a.out.js": 19099, - "a.out.js.gz": 7930, + "a.out.js": 19101, + "a.out.js.gz": 7933, "a.out.nodebug.wasm": 145729, "a.out.nodebug.wasm.gz": 54945, - "total": 164828, - "total_gz": 62875, + "total": 164830, + "total_gz": 62878, "sent": [ "_abort_js", "_tzset_js", diff --git a/test/codesize/test_codesize_cxx_lto.json b/test/codesize/test_codesize_cxx_lto.json index 308be06dbfe4a..d07c6925e5f67 100644 --- a/test/codesize/test_codesize_cxx_lto.json +++ b/test/codesize/test_codesize_cxx_lto.json @@ -1,10 +1,10 @@ { - "a.out.js": 18562, - "a.out.js.gz": 7668, + "a.out.js": 18564, + "a.out.js.gz": 7670, "a.out.nodebug.wasm": 101954, "a.out.nodebug.wasm.gz": 39462, - "total": 120516, - "total_gz": 47130, + "total": 120518, + "total_gz": 47132, "sent": [ "a (emscripten_resize_heap)", "b (_setitimer_js)", diff --git a/test/codesize/test_codesize_cxx_mangle.json b/test/codesize/test_codesize_cxx_mangle.json index fa71038445551..6ee20ff2d62c4 100644 --- a/test/codesize/test_codesize_cxx_mangle.json +++ b/test/codesize/test_codesize_cxx_mangle.json @@ -1,10 +1,10 @@ { - "a.out.js": 23223, - "a.out.js.gz": 8984, + "a.out.js": 23225, + "a.out.js.gz": 8986, "a.out.nodebug.wasm": 238957, "a.out.nodebug.wasm.gz": 79847, - "total": 262180, - "total_gz": 88831, + "total": 262182, + "total_gz": 88833, "sent": [ "__cxa_begin_catch", "__cxa_end_catch", diff --git a/test/codesize/test_codesize_cxx_noexcept.json b/test/codesize/test_codesize_cxx_noexcept.json index 5f42ba6c192f1..d2b27cfde08b3 100644 --- a/test/codesize/test_codesize_cxx_noexcept.json +++ b/test/codesize/test_codesize_cxx_noexcept.json @@ -1,10 +1,10 @@ { - "a.out.js": 19193, - "a.out.js.gz": 7970, + "a.out.js": 19195, + "a.out.js.gz": 7973, "a.out.nodebug.wasm": 134661, "a.out.nodebug.wasm.gz": 50777, - "total": 153854, - "total_gz": 58747, + "total": 153856, + "total_gz": 58750, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_cxx_wasmfs.json b/test/codesize/test_codesize_cxx_wasmfs.json index e2c697449f464..ff569694f2807 100644 --- a/test/codesize/test_codesize_cxx_wasmfs.json +++ b/test/codesize/test_codesize_cxx_wasmfs.json @@ -1,10 +1,10 @@ { - "a.out.js": 7033, - "a.out.js.gz": 3310, - "a.out.nodebug.wasm": 172736, - "a.out.nodebug.wasm.gz": 63329, - "total": 179769, - "total_gz": 66639, + "a.out.js": 7024, + "a.out.js.gz": 3312, + "a.out.nodebug.wasm": 172714, + "a.out.nodebug.wasm.gz": 63316, + "total": 179738, + "total_gz": 66628, "sent": [ "__cxa_throw", "_abort_js", diff --git a/test/codesize/test_codesize_file_preload.expected.js b/test/codesize/test_codesize_file_preload.expected.js index bec5c6ff55130..885599e146a08 100644 --- a/test/codesize/test_codesize_file_preload.expected.js +++ b/test/codesize/test_codesize_file_preload.expected.js @@ -625,13 +625,10 @@ var initRandomFill = () => { var nodeCrypto = require("node:crypto"); return view => nodeCrypto.randomFillSync(view); } - return view => crypto.getRandomValues(view); + return view => (crypto.getRandomValues(view), 0); }; -var randomFill = view => { - // Lazily init on the first invocation. - (randomFill = initRandomFill())(view); -}; +var randomFill = view => (randomFill = initRandomFill())(view); var PATH_FS = { resolve: (...args) => { diff --git a/test/codesize/test_codesize_file_preload.json b/test/codesize/test_codesize_file_preload.json index 1dca3b3bd4f1d..b7b9f15a04e0e 100644 --- a/test/codesize/test_codesize_file_preload.json +++ b/test/codesize/test_codesize_file_preload.json @@ -1,10 +1,10 @@ { - "a.out.js": 22140, - "a.out.js.gz": 9186, + "a.out.js": 22142, + "a.out.js.gz": 9188, "a.out.nodebug.wasm": 1648, "a.out.nodebug.wasm.gz": 939, - "total": 23788, - "total_gz": 10125, + "total": 23790, + "total_gz": 10127, "sent": [ "a (fd_write)" ], diff --git a/test/codesize/test_codesize_files_js_fs.json b/test/codesize/test_codesize_files_js_fs.json index fb4dc4fedcfe0..fbec85b5ddf28 100644 --- a/test/codesize/test_codesize_files_js_fs.json +++ b/test/codesize/test_codesize_files_js_fs.json @@ -1,10 +1,10 @@ { - "a.out.js": 17833, - "a.out.js.gz": 7311, + "a.out.js": 17835, + "a.out.js.gz": 7313, "a.out.nodebug.wasm": 381, "a.out.nodebug.wasm.gz": 260, - "total": 18214, - "total_gz": 7571, + "total": 18216, + "total_gz": 7573, "sent": [ "a (fd_write)", "b (fd_read)", diff --git a/test/codesize/test_codesize_files_wasmfs.json b/test/codesize/test_codesize_files_wasmfs.json index 7f762478c571d..7e9e29dc554e9 100644 --- a/test/codesize/test_codesize_files_wasmfs.json +++ b/test/codesize/test_codesize_files_wasmfs.json @@ -1,10 +1,10 @@ { - "a.out.js": 5475, + "a.out.js": 5466, "a.out.js.gz": 2578, - "a.out.nodebug.wasm": 58440, - "a.out.nodebug.wasm.gz": 18075, - "total": 63915, - "total_gz": 20653, + "a.out.nodebug.wasm": 58418, + "a.out.nodebug.wasm.gz": 18067, + "total": 63884, + "total_gz": 20645, "sent": [ "a (emscripten_date_now)", "b (emscripten_err)", diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index 94e93d273ce87..d01f86aa85cd3 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -1,10 +1,10 @@ { - "a.out.js": 26183, - "a.out.js.gz": 11173, + "a.out.js": 26186, + "a.out.js.gz": 11175, "a.out.nodebug.wasm": 17668, "a.out.nodebug.wasm.gz": 8921, - "total": 43851, - "total_gz": 20094, + "total": 43854, + "total_gz": 20096, "sent": [ "__syscall_stat64", "emscripten_resize_heap", diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index 2a4df77df86ab..7a59c957b3b0a 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,7 +1,7 @@ { - "a.out.js": 244411, - "a.out.nodebug.wasm": 577484, - "total": 821895, + "a.out.js": 244320, + "a.out.nodebug.wasm": 577447, + "total": 821767, "sent": [ "IMG_Init", "IMG_Load", diff --git a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json index 7fd4a41593664..f1b1c4ce5a716 100644 --- a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json +++ b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json @@ -1,10 +1,10 @@ { "a.html": 515, "a.html.gz": 355, - "a.js": 4313, - "a.js.gz": 2220, - "a.wasm": 1324, - "a.wasm.gz": 892, - "total": 6152, - "total_gz": 3467 + "a.js": 4452, + "a.js.gz": 2294, + "a.wasm": 1360, + "a.wasm.gz": 910, + "total": 6327, + "total_gz": 3559 } diff --git a/test/webaudio/audioworklet.c b/test/webaudio/audioworklet.c index 979b59bb666ff..b80c61b83e11c 100644 --- a/test/webaudio/audioworklet.c +++ b/test/webaudio/audioworklet.c @@ -1,5 +1,6 @@ #include #include +#include /* Steps to use Wasm-based AudioWorklets: 1. Create a Web Audio AudioContext either via manual JS code and calling @@ -30,7 +31,13 @@ int lastTlsVariableValueInAudioThread = 1; #endif // This function will be called for every fixed-size buffer of audio samples to be processed. -bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) { +bool ProcessAudio(int numInputs, + const AudioSampleFrame* inputs, + int numOutputs, + AudioSampleFrame* outputs, + int numParams, + const AudioParamFrame* params, + void* userData) { #ifdef TEST_AND_EXIT // Only running in the test harness, see main_thread_tls_access() assert(testTlsVariable == lastTlsVariableValueInAudioThread); @@ -39,10 +46,18 @@ bool ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, assert(emscripten_current_thread_is_audio_worklet()); #endif + // Verify that getentropy fails gracefully (i.e. returns non-zero) when called + // inside a worklet (where crypto.getRandomValues is not supported); + unsigned char bytes[16]; + int rtn = getentropy(bytes, sizeof(bytes)); + assert(rtn != 0); + // Produce noise in all output channels. - for(int i = 0; i < numOutputs; ++i) - for(int j = 0; j < outputs[i].samplesPerChannel*outputs[i].numberOfChannels; ++j) + for (int i = 0; i < numOutputs; ++i) { + for (int j = 0; j < outputs[i].samplesPerChannel*outputs[i].numberOfChannels; ++j) { outputs[i].data[j] = (rand() / (float)RAND_MAX * 2.0f - 1.0f) * 0.3f; + } + } // We generated audio and want to keep this processor going. Return false here to shut down. return true;