Skip to content

new Function drops non-string arguments instead of calling ToString: new Function(['a','b'], body) loses its parameters, and spread argument lists produce an empty body #10424

Closed

Description

@proggeramlug

Found by the package audit (compiling real npm packages from source instead of Perry's native bindings) on
Perry e6dcb62 (v0.5.1587), Linux x64. The Function constructor must apply ToString to every argument, so new Function(['a','b'], body) has parameters a,b. Perry treats any non-string argument as an empty string. The resulting function has no parameters (ReferenceError: a is not defined when called), or no body when the arguments are spread. The bare-call form with a constant body returns undefined.

Reproduction

main.ts:

const body = ["return a", "+", "b"].join(" "); // any runtime-built body
const t = (label: string, mk: () => any) => {
  try { const f = mk(); console.log(label, typeof f, typeof f === "function" ? f(2, 3) : ""); }
  catch (e) { console.log(label, "THREW", String(e)); }
};
t("new Function('a,b', body)                 ", () => new Function("a,b", body)); // control
t("new Function(['a','b'], body)             ", () => new Function(["a", "b"] as any, body));
t("new Function(['a','b'], 'return a + b')   ", () => new Function(["a", "b"] as any, "return a + b"));
t("Function(['a','b'], 'return a + b')       ", () => Function(["a", "b"] as any, "return a + b"));
t("new Function({toString: () => 'a,b'}, body)", () => new Function({ toString: () => "a,b" } as any, body));
t("new Function(...['a', 'b', body])         ", () => new Function(...["a", "b", body]));
t("new Function('a', ...['b', body])         ", () => new Function("a", ...["b", body]));
perry compile main.ts -o out && ./out
PERRY_NO_AUTO_OPTIMIZE=1 perry compile main.ts -o out2 && ./out2   # identical result

Expected (Node 26.5.1)

new Function('a,b', body)                  function 5
new Function(['a','b'], body)              function 5
new Function(['a','b'], 'return a + b')    function 5
Function(['a','b'], 'return a + b')        function 5
new Function({toString: () => 'a,b'}, body) function 5
new Function(...['a', 'b', body])          function 5
new Function('a', ...['b', body])          function 5

Actual (Perry, both modes)

new Function('a,b', body)                  function 5
new Function(['a','b'], body)              THREW ReferenceError: a is not defined
new Function(['a','b'], 'return a + b')    THREW ReferenceError: a is not defined
Function(['a','b'], 'return a + b')        undefined 
new Function({toString: () => 'a,b'}, body) THREW ReferenceError: a is not defined
new Function(...['a', 'b', body])          function undefined
new Function('a', ...['b', body])          function undefined

Impact

Notes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    package-auditFound by the 2026 package audit: compiling real npm packages from source instead of native bindings

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions