Skip to content

Fix Function.prototype.toString for a revoked proxy - #1912

Open
bardrop wants to merge 1 commit into
quickjs-ng:masterfrom
bardrop:fix-tostring-revoked-proxy
Open

bardrop wants to merge 1 commit into
quickjs-ng:masterfrom
bardrop:fix-tostring-revoked-proxy

Conversation

@bardrop

@bardrop bardrop commented Nov 12, 2026

Copy link
Copy Markdown

Fixes #1737

js_function_toString builds the native-code string from JS_GetProperty(this, "name"). When this is a callable proxy, that read goes through the proxy:

const r = Proxy.revocable(function () {}, {});
r.revoke();
Function.prototype.toString.call(r.proxy); // TypeError: revoked proxy

const p = new Proxy(function f() {}, { get(t, k) { console.log("get", k); return Reflect.get(t, k); } });
Function.prototype.toString.call(p);       // logs "get name"

A proxy that wraps a function keeps [[Call]] after it is revoked, so IsCallable is still true and Function.prototype.toString must return a NativeFunction string. The spec does not read name there, so the get trap should not run either.

The change uses an empty name for proxies (function () {\n [native code]\n}). V8, SpiderMonkey and JavaScriptCore also print a nameless native function for proxies. Non-proxy functions are unchanged.

Tests: added cases to test_function() in tests/test_builtin.js (revoked proxy, get trap not called, non-callable proxy still throws TypeError). They fail before the change. make test gives the same result as on master (only test_std.js test_poll_handler_order fails on my macOS machine, with or without this change). A local test262 run of built-ins/Function/prototype/toString (0/160 errors) and built-ins/Proxy (0/606 errors) passes.

js_function_toString read "name" through the receiver with
JS_GetProperty. For a revoked callable proxy that throws
"TypeError: revoked proxy", and for a live proxy it calls the get trap.
Per ECMA-262 a proxy that wraps a function keeps [[Call]] after revoke,
so IsCallable is true and toString must return a NativeFunction string
without touching the handler. Use an empty name for proxies, which
matches V8, SpiderMonkey and JavaScriptCore.

Fixes: quickjs-ng#1737

This branch has not been deployed

No deployments
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.

Function.prototype.toString throws for a revoked Proxy

1 participant