UNKNOWN_CODE に「スクリプト ブレーカー」を埋め込むことができます。何かのようなもの:
;setTimeout(function() { throw new Error("Execution time limit reached!") }, 2000);
したがって、全体は次のようになります。
var UNKNOWN_CODE = "while(true){}";
var scriptBreaker = ';setTimeout(function() { throw new Error("Execution time limit reached!") }, 2000);';
var vm = require("vm");
var obj = {};
var ctx = vm.createContext(obj);
var script = vm.createScript(scriptBreaker + UNKNOWN_CODE);
try {
script.runInNewContext(ctx);
console.log("Finished");
}
catch (err) {
console.log("Timeout!");
// Handle Timeout Error...
}
アップデート:
さらにテストを重ねた結果、信頼できるアプローチはプロセスを指摘された Esailja として使用することであるという結論に達しました。しかし、私はそれを少し違ったやり方でやっています。
メインアプリには、次のようなコードがあります。
var cp = require('child_process');
function runUnsafeScript(script, callback) {
var worker = cp.fork('./script-runner', [script]);
worker.on('message', function(data) {
worker.kill();
callback(false, data);
});
worker.on('exit', function (code, signal) {
callback(new Error(code), false);
});
worker.on('error', function (err) {
callback(err, false);
});
setTimeout(function killOnTimeOut() {
worker.kill();
callback(new Error("Timeout"), false);
}, 5000);
}
script-runner.js では、次のようになります。
var vm = require("vm");
var script = vm.createScript( process.argv[2] );
var obj = { sendResult:function (result) { process.send(result); process.exit(0); } };
var context = vm.createContext(obj);
script.runInNewContext(context);
process.on('uncaughtException', function(err) {
process.exit(1);
});
このアプローチにより、次の目標を達成することができました。
- 限られたコンテキストでスクリプトを実行する
- デッド ループと例外の問題を回避する
- 多くの(ハードウェアによって制限される)安全でないスクリプトを同時に実行して、相互に干渉しないようにする
- スクリプトの実行結果をメインアプリに渡してさらに処理する