laverdet / isolated-vm

Secure & isolated JS environments for nodejs
ISC License
2.19k stars 154 forks source link

Reference: Pass function from isolate to host #493

Closed rakeshar3796 closed 2 months ago

rakeshar3796 commented 2 months ago

Is Your Question Already Answered?

Personal Diagnostics

Please answer the following questions:

JavaScript includes a setTimeout function:

Functions are a type of primitive value in JavaScript:

Objects can be shared between isolates:

The Code

import ivm from "isolated-vm";

async function main() {
  function host_fn(_options) {
    console.info("__OPTIONS__", _options); // logs Reference {}
    const options = _options.copySync(); // expected to get the value from reference but getting error
    const { arrayBuffer } = options;
    arrayBuffer();
  }

  const code = `
    async function execute() {
      let abc = {
        arrayBuffer: function () {
            return "arraybuffer"
        }
      };
      __host_fn_call(abc);
    };
    execute();
  `;

  async function runScriptInIsolate() {
    const isolate = new ivm.Isolate({ memoryLimit: 128 });
    const context = await isolate.createContext();

    context.global.setSync("log", (...args) => {
      console.log(...args);
    });

    await context.evalClosure(
      `globalThis.__host_fn_call = (...args) => $0.applySync(null, args, { arguments: { reference: true }, result: { promise: true } })`,
      [new ivm.Reference(host_fn)]
    );

    // Execute the script in the isolate
    const script = await isolate.compileScriptSync(code);
    const result = await script.runSync(context, {
      promise: true,
      reference: true,
    });

    // Return the result
    return result;
  }

  runScriptInIsolate()
    .then((result) => {
      console.log("Result:", result.copySync());
    })
    .catch((err) => {
      console.error("Error:", err);
    });
}

main();

My intention here is to pass an function as an argument from the isolate to the host and when i'm doing this i've faced an error "could not be cloned" when the arguments options is set to copy:true for __host_fn_call but when i change it to reference am still getting the error. Is this the right approach or am i missing anything here?

laverdet commented 2 months ago

You cannot clone a function. Think of copy:true as JSON.stringify with additional handling for Map, Set, bigint, etc. It is the structured clone algorithm. What would it even mean to clone a function which is a closure that references the entire nodejs heap?

rakeshar3796 commented 2 months ago

Understood @laverdet but for this scenario i'll handle this with some workaround because it's in my control but this same happens in the user script there i won't have control like

let abc = {
  arrayBuffer: function () {
    return "arraybuffer"
  }
};
log("LOGGER", abc);

if they try to log i'll face the same problem, is this actually a problem or am missing anything?