From c72a3e528d7909c212596b52de5f9a5fe0161f17 Mon Sep 17 00:00:00 2001 From: webreflection Date: Tue, 15 Jul 2025 10:40:15 +0200 Subject: [PATCH] webassembly/objpyproxy: Avoid throwing on implicit symbols access. This commit improves get handling by guarding against implicit unknown symbols accessed directly by specific JS native APIs. Fixes issue #17657. Signed-off-by: Andrea Giammarchi --- ports/webassembly/objpyproxy.js | 53 ++++++++++---------- tests/ports/webassembly/py_proxy_get.mjs | 14 ++++++ tests/ports/webassembly/py_proxy_get.mjs.exp | 5 ++ 3 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 tests/ports/webassembly/py_proxy_get.mjs create mode 100644 tests/ports/webassembly/py_proxy_get.mjs.exp diff --git a/ports/webassembly/objpyproxy.js b/ports/webassembly/objpyproxy.js index 0eafd0dec5..64703d78a5 100644 --- a/ports/webassembly/objpyproxy.js +++ b/ports/webassembly/objpyproxy.js @@ -165,34 +165,35 @@ const py_proxy_handler = { if (prop === "_ref") { return target._ref; } - if (prop === "then") { - return null; - } - if (prop === Symbol.iterator) { - // Get the Python object iterator, and return a JavaScript generator. - const iter_ref = Module.ccall( - "proxy_c_to_js_get_iter", - "number", - ["number"], - [target._ref], - ); - return function* () { - const value = Module._malloc(3 * 4); - while (true) { - const valid = Module.ccall( - "proxy_c_to_js_iternext", - "number", - ["number", "pointer"], - [iter_ref, value], - ); - if (!valid) { - break; + // ignore both then and all symbols but Symbol.iterator + if (prop === "then" || typeof prop !== "string") { + if (prop === Symbol.iterator) { + // Get the Python object iterator, and return a JavaScript generator. + const iter_ref = Module.ccall( + "proxy_c_to_js_get_iter", + "number", + ["number"], + [target._ref], + ); + return function* () { + const value = Module._malloc(3 * 4); + while (true) { + const valid = Module.ccall( + "proxy_c_to_js_iternext", + "number", + ["number", "pointer"], + [iter_ref, value], + ); + if (!valid) { + break; + } + yield proxy_convert_mp_to_js_obj_jsside(value); } - yield proxy_convert_mp_to_js_obj_jsside(value); - } - Module._free(value); - }; + Module._free(value); + }; + } + return undefined; } const value = Module._malloc(3 * 4); diff --git a/tests/ports/webassembly/py_proxy_get.mjs b/tests/ports/webassembly/py_proxy_get.mjs new file mode 100644 index 0000000000..825de7cabe --- /dev/null +++ b/tests/ports/webassembly/py_proxy_get.mjs @@ -0,0 +1,14 @@ +// Test ` get ` on the JavaScript side, which tests PyProxy.get. + +const mp = await (await import(process.argv[2])).loadMicroPython(); + +mp.runPython(` +x = {"a": 1} +`); + +const x = mp.globals.get("x"); +console.log(x.a === 1); +console.log(x.b === undefined); +console.log(typeof x[Symbol.iterator] === "function"); +console.log(x[Symbol.toStringTag] === undefined); +console.log(x.then === undefined); diff --git a/tests/ports/webassembly/py_proxy_get.mjs.exp b/tests/ports/webassembly/py_proxy_get.mjs.exp new file mode 100644 index 0000000000..36c7afad66 --- /dev/null +++ b/tests/ports/webassembly/py_proxy_get.mjs.exp @@ -0,0 +1,5 @@ +true +true +true +true +true