fix(core): make registerPlugin proxy non-thenable to prevent silent await hangs - #8582
Open
bun-unsafe wants to merge 1 commit into
Open
fix(core): make registerPlugin proxy non-thenable to prevent silent await hangs#8582bun-unsafe wants to merge 1 commit into
bun-unsafe wants to merge 1 commit into
Conversation
…wait hangs The plugin Proxy get trap returns a callable method wrapper for every property name outside its allowlist. That allowlist already special-cases $$typeof so React does not misclassify a plugin as a Lazy/Promise, but it does not cover the language-level thenable probe: when a value is adopted into a Promise (e.g. a plugin proxy returned from an async function), the runtime calls proxy.then(resolve, reject) per PromiseResolveThenableJob. The get trap answered that with a method wrapper, so the engine treated the proxy as a thenable and dispatched a then() call across the bridge. On plugins without a native then method the call never settles, so the outer await hangs forever with no error at the call site. Return undefined for then/catch/finally, mirroring the $$typeof fix: a Capacitor plugin is not a Promise, so these names must not produce callables. Regular plugin methods are unaffected. Fixes ionic-team#8469 Closes ionic-team#8472
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The plugin
ProxyinregisterPlugin()(core/src/runtime.ts) returns a callable method wrapper for every property name that isn't in its allowlist. The allowlist already special-cases$$typeof(react/react#20030) so React doesn't misclassify a plugin as a Lazy/Promise — but it doesn't cover the language-level thenable probe.When any value is adopted into a Promise — most commonly a plugin proxy returned from an
asyncfunction — the engine runsPromiseResolveThenableJob, which accesses.thenand, if callable, invokesproxy.then(resolve, reject).For the plugin proxy:
proxy.thenhits thegettrap'sdefaultbranch and returns a method wrapper.proxy.then(resolve, reject).then()method call across the bridge. Plugins don't implementthen, so the call never settles — the outerawaithangs forever, and thetry/catchat the call site can never reach the failure.This is the same class of issue the
$$typeofspecial case already fixed, but triggered by the language's own thenable adoption machinery instead of React's userland check.Fix
Return
undefinedforthen,catch, andfinallyin thegettrap, mirroring the existing$$typeofhandling: a Capacitor plugin is not a Promise, so these names must not produce callables.Why this is safe:
thenis probed by the language on every value adopted into a Promise; returningundefinedmakes the proxy a plain non-thenable, soawaitresolves to the proxy itself — same semantics as a plain object..then(...)on real promises returned by plugin methods is unaffected — that's a Promise method, not a proxyget.then/catch/finally; such names would already be hostile to Promise-using callers.Testing
Added a regression test to
core/src/tests/runtime.spec.ts(verified it fails onmainwithout the patch):Full suite passes:
cd core && npm run build && npm test— 52/52 (was 51, +1).Fixes #8469
Closes #8472