Open kiddkai opened 1 year ago
@laverdet I found a minimum reproducable script to break it.
Currently I put it in the ./tests
folder and run it.
'use strict';
let ivm = require('isolated-vm');
const resData = async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(JSON.stringify({ filePath: '/test', code: 'run();' }));
}, 10);
});
};
function makeIsolate() {
let isolate = new ivm.Isolate;
let context = isolate.createContextSync();
let global = context.global;
return { isolate, context, global };
}
const main = async () => {
// Basic test.. tests unlocking
let env = makeIsolate();
env.global.setSync('ivm', ivm);
env.global.setSync('ctx', env.context);
env.global.setSync('fn', new ivm.Reference(async function () {
const result = await resData();
return result;
}));
env.global.setSync('log', new ivm.Callback(function (...args) {
console.log(...args);
}));
const script = env.isolate.compileScriptSync(`
counter = 0;
function run() {
if (counter > 128) return;
counter++;
const res = JSON.parse(fn.applySyncPromise(undefined, []));
log(counter, res.filePath);
ctx.evalSync(res.code)
return '';
}
run();
`);
for (let i = 0; i < 100; i++) {
await script.run(env.context);
}
console.log('pass');
};
main();
Currently, I found when the call stack is deep-ish inside the isolated-vm. There's a chance to trigger a segfaults when main thread(node) finish the job, and the paused isolated-vm thread resume that receive an invalid address to the passed back value.
I tried to replicate this behaviour in a smaller reproducable script but failed so far. I will report what I have for now, will update the thread when I am getting more info.
What I am doing with the isolated-vm was:
isolated-vm thread
runs entry code, when the entry code hits arequire
call, make aapplySyncPromise
tomain thread
.main thread
returns the resolved dependency info.isolated-vm
thread ask for the compiled code frommain thread
again also viaapplySyncPromise
.isolated-vm
thread eval theresolved code
.This generates a relative deep call stacks, it also segfault ramdomly. But what I've observed when crashing is that the passed value, currently is
string
only, the pointer is pointing to an invalid address doesn't contain anything whenisolated-vm
thread gets the result fromsyncPromise
.Screenshot in vscode for stacktrace, and the invalid addr on the transfer back value: "should be a json string".
It happen randomly from different threads, sometimes
main
thread, sometimesisolated-vm
thread.When SegFault happen in main thread
A screenshot about the js callstack, breaks while running
AsyncCallback
:When it happen in the
main
thread, it seem like the value is passed correctly based on js stack trace:While broken when trying to unlock:
When SegFault happen in
isolated-vm
threadMain thread
stack trace shows correct value:Then in the
isolated-vm
thread, it gets:Interestingly, the
main
thread'sexit frame
seems to run code that should be run in theisolated-vm
thread. When theisolated-vm thread
received the value, it runsJSON.parse
.