Skip to content

Resolve flash_proxy trap overrides mangled into the public namespace - #13

Open
neilrackett wants to merge 1 commit into
awayfl:devfrom
mesmotronic:fix/proxy-public-mangled-trap-overrides
Open

Resolve flash_proxy trap overrides mangled into the public namespace#13
neilrackett wants to merge 1 commit into
awayfl:devfrom
mesmotronic:fix/proxy-public-mangled-trap-overrides

Conversation

@neilrackett

Copy link
Copy Markdown

Proxy: resolve flash_proxy trap overrides mangled into the public namespace

This PR fixes flash.utils.Proxy subclasses whose trap overrides
(callProperty, getProperty, setProperty, …) were unreachable, so any
dynamic property access or call on the proxy died with the base-class errors
#2088–#2096 ("The Proxy class does not implement trap. It must be
overridden by a subclass.") — even though the subclass clearly overrides them.

The bug

ASProxy dispatches traps by looking up proxyPrefix + name, i.e. the
flash_proxy-namespace mangled property (e.g. $G_v0hLCcallProperty). That's
where classInitializer installs the base throwers, and where subclass
overrides are expected to shadow them.

In practice, though, the override trait from the SWF's ABC can be installed
under a public-namespace mangled name instead ($BgcallProperty),
depending on how the ABC's flash_proxy namespace is interned. The prototype
chain then looks like this:

subclass tPrototype:  $BgcallProperty        ← the app's override (never found)
Proxy tPrototype:     $G_v0hLCcallProperty   ← base thrower (always found)

…and every dynamic access on the proxy throws.

The fix

Route all trap dispatch through a small resolver that prefers a
public-mangled override when one exists, falling back to the
flash_proxy-mangled name:

private _proxyTrap(name: string): Function {
    return (<any> this)['$Bg' + name] || (<any> this)[proxyPrefix + name];
}

The resolved trap is invoked with an explicit receiver (.call(this, …) /
.apply(this, …)) — the previous inline this[key](…) form kept the
receiver implicitly, so the rewrite preserves it deliberately: the trap
bodies are compiled AS3 whose scope chain must see the proxy instance.

Real-world impact

Found while reviving an AS3/Flex-era business app (compiled ~2012) whose
entire RPC layer is a Proxy subclass — the AMFPHP/Flex idiom of
service.anyMethodName(args) routed through flash_proxy::getProperty /
callProperty. Under the runtime the app hung on its preloader forever
because every service call threw #2090 (swallowed by a Timer handler). With
this change, all dynamic service calls route correctly and the app runs
end-to-end.

Companion PR in playerglobal (independent, but the same app needs both):
Flash Remoting (AMF over HTTP) support in NetConnection.

…espace

Subclass overrides of the flash_proxy traps (getProperty, setProperty,
callProperty, hasProperty, deleteProperty, nextName, nextValue,
nextNameIndex) are expected to shadow the base thrower at
proxyPrefix + name, but the override trait can be installed with a
public-namespace mangled name ($Bg + name) instead, depending on how the
SWF's ABC interns the flash_proxy namespace. The base thrower then wins
the lookup, and any dynamic property access or call on a Proxy subclass
dies with errors #2088-#2096 ('The Proxy class does not implement
<trap>. It must be overridden by a subclass.').

Route all trap dispatch through a resolver that prefers a public-mangled
override when one exists, and invoke it with an explicit receiver
(.call/.apply) so the trap body's scope chain sees the proxy instance.

Observed in the wild with an AS3/Flex-era app (compiled ~2012) whose
Proxy-based RPC service layer was completely non-functional under the
runtime; with this change all dynamic service calls route correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant