Skip to content

Function and indirect eval should not capture context from where they are called.Β #3160

@nicolo-ribaudo

Description

@nicolo-ribaudo

Description: Consider these two programs:

  • // 1/entrypoint.js
    import { createFunction } from "./folder/mod.js";
    createFunction(str)();
    // 1/folder/mod.js
    export const createFunction = Function;
  • // 2/entrypoint.js
    import { createFunction } from "./folder/mod.js";
    createFunction(str)();
    // 2/folder/mod.js
    export const createFunction = (...args) => Function(...args);

For any given string str, their behavior should be identical. Only direct eval should capture context from where it's being called, while Function and indirect eval (and setTimeout, even if it's in HTML) should not.

However, Function("import(...)") is defined to use the Function/(0, eval)'s caller as import()'s referrer, introducing a dynamic scope case other than direct eval.

eshost Output:

Browsers behavior varies:

  • Firefox implements the spec for Function, eval, and setTimeout
  • Chrome implements the spec for Function and eval, but not setTimeout
  • Safari does not implement the spec, and does not propagate the active script or module.

You can find a test with various cases at https://github.com/nicolo-ribaudo/function-dynamic-scoping.

Proposed behavior:

In all these cases, import()'s referrer should not capture any script or module, and instead fallback to using the current realm as the referrer.

I believe that this is what is already happening in the following case, as described in #871:

Promise.resolve("import(...)").then(eval);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions