laverdet / isolated-vm

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

Capture stdout/stderr from WebAssembly #426

Closed skhaz closed 1 year ago

skhaz commented 1 year ago

I have this C++ code

#include <iostream>
int main()
{
  std::cout << "Hello World!" << std::endl;
  return 0;
}

I compile it with the command

emcc -s ENVIRONMENT=shell -s WASM=1 -s MODULARIZE=1 main.cpp -o /tmp/main.js

Then, I use isolated-vm to run it

const fs = require("fs");
const ivm = require("isolated-vm");
const isolate = new ivm.Isolate({ memoryLimit: 16 });

const context = isolate.createContextSync();

const jail = context.global;
jail.setSync("global", jail.derefInto());
jail.setSync("log", function (...args) {
  console.log(...args);
});

const hostile = isolate.compileScriptSync(
  fs.readFileSync("/tmp/main.js", "utf8")
);

hostile.run(context).catch((err) => console.error(err));

It returns undefined and prints nothing.

Is there some way to capture the stdout and stdin? And even better, provide a stdin?

Thank you in advanced

laverdet commented 1 year ago

emscripten does a bunch of automatic stuff in the background which you should probably take control of. I recommend implementing a WASI backend for your compiled WebAssembly and directly using the WebAssembly constructors. You basically have to implement a small subset of the libc library where you provide the means to write to scatter/gather arrays of arrays.

It's a lot of legwork but not too bad. I did this for xxscreeps: https://github.com/laverdet/xxscreeps/blob/52e4cb07b5aad57da1a1654ffec17e47f1aa493b/src/driver/runtime/wasi/index.ts https://github.com/laverdet/xxscreeps/blob/52e4cb07b5aad57da1a1654ffec17e47f1aa493b/src/driver/runtime/module.ts#L80-L203

But the reason you aren't seeing output is because emscripten uses console.log and you have exported log instead.

skhaz commented 1 year ago

Thank you so much.