Calling toString on function proxy throws TypeError exception

Allen Wirfs-Brock allen at
Mon Oct 26 17:17:43 UTC 2015

> On Oct 23, 2015, at 6:43 AM, Claude Pache <claude.pache at> wrote:
> Almost every method found on `Function.prototype` "works" (or, at least, does not throw a TypeError before trying to work) if and only if the target is callable, or if and only if `typeof` applied to the target produces `"function"`. 
> That should not be different for `Function.prototype.toString()`. Even if "working" means producing a useless string à la `"function () { [native code] }"`.
> —Claude

Right, I should have look closer at the actual spec for  call, apply, and blind rather than depending upon memory.  The reason they work on proxies is that they only depend upon the MOP API of their this object. In other words, they are generic across  all object that have a [[Call]] internal method.

Function.prototype.toString is different in that it is dependent upon the actual internal structure of the object is is applied to rather than the object’s MOP API. This is necessary because F.p.toString must access information (the source code of the function or the ability to recreate it) that is not available through the MOP.  As I’ve mentioned in earlier messages, F.p.toString is in this regard like all other methods that directly access private internal state.  

F.p.toString could be respecified to explicitly recognize proxies and drill through them but it isn’t clear why F.p.toString should be singled out from all other private state accessing buiit-in methods in this regard. 

But, let’s assume we did make F.p.toString drill through callable proxies.  What are the implications.

First remember, that a callable proxy can only be created on a target object that already has a [[Call]] internal method. The target might itself be a callable proxy, but ultimately the chain of targets must reach an object that has a primitive [[Call]] behavior.  This would normally be either an ECMAScript function object or a built-in function object.

So, while it is perfectly reasonable to define a callable proxy that, for example, in its [[Call]] handler runs a Lisp interpreter over a captured S-expression, such a proxy   must either directly or indirectly have as its target an ECMAScript function. If you were defining such a proxy where the Lisp interpreter is embedded within its [[Call]] handler, you might use something like: `function() {}` as the target. If you apply an enhanced proxy drill throughing F.p.toString to such a proxy you would get the source code for `function() {}`.  How is that useful?

Another way, to implement our Lisp interpreting proxy would be to use as the target an ECMAScript function that actually implements the Lisp interpreter. In that case, the [[Call]] handler would simply call the target function passing the captured S-expression to it as an argument.  If you apply an enhanced proxy drill throughing F.p.toString to that sort of a proxy you would get back the source code for the Lisp interpreter. This seems potentially harmful.  Revealing the source code of the Lisp interpreter might reveal exploitable secrets. Heck, the very fact that a Lisp interpreter is being used might be a secret.

So, why would we want to do this?


More information about the es-discuss mailing list