Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js vm: How to cancel Script.runInNewContext()?

Tags:

node.js

v8

I want to use the vm module as a safe way to run external code. It works pretty well, but there is one issue left:

var UNKNOWN_CODE = "while(true){}";

var vm = require("vm");

var obj = {};
var ctx = vm.createContext(obj);

var script = vm.createScript(UNKNOWN_CODE);

script.runInNewContext(ctx);

console.log("finished"); //never executed

Is there any way to cancel the execution (e.g. if it lasts for more than 5s)?

Thanks in advance!

like image 270
muffel Avatar asked Jul 25 '12 14:07

muffel


1 Answers

You need to run it in a separate process, for example:

master.js:

var cluster = require('cluster');

cluster.setupMaster({
  exec : "runner.js",
  args : process.argv.slice(2),
  silent : false
});
//This will be fired when the forked process becomes online
cluster.on( "online", function(worker) {
    var timer = 0;

    worker.on( "message", function(msg) {
        clearTimeout(timer); //The worker responded in under 5 seconds, clear the timeout
        console.log(msg);
        worker.destroy(); //Don't leave him hanging 

    });
    timer = setTimeout( function() {
        worker.destroy(); //Give it 5 seconds to run, then abort it
        console.log("worker timed out");
    }, 5000);

    worker.send( 'while(true){}' ); //Send the code to run for the worker
});
cluster.fork();

runner.js:

//The runner.js is ran in a separate process and just listens for the message which contains code to be executed
process.on('message', function( UNKNOWN_CODE ) {

    var vm = require("vm");

    var obj = {};
    var ctx = vm.createContext(obj);

    var script = vm.createScript(UNKNOWN_CODE);

    script.runInNewContext(ctx);

    process.send( "finished" ); //Send the finished message to the parent process
});

To run this example, place those files in the same folder and dir to it and run

node master.js

You should see "worker timed out" message after 5 seconds. If you change it to 'while(false){}' the worker will execute the code immediately and you should see "finished" instead.

Cluster docs

like image 58
Esailija Avatar answered Oct 21 '22 05:10

Esailija