diff --git a/lib/main.js b/lib/main.js index d7f96e3..50edfe1 100644 --- a/lib/main.js +++ b/lib/main.js @@ -149,6 +149,20 @@ class VMScript { return this; } + _runInVM(context) { + return this._compiledVM.runInContext(context, { + filename: this.filename, + displayErrors: false + }); + } + + _runInNodeVM(context) { + return this._compiledNodeVM.runInContext(context, { + filename: this.filename, + displayErrors: false + }); + } + } function loadScript(filename) { @@ -159,9 +173,28 @@ function loadScript(filename) { const SCRIPT_CACHE = { cf: loadScript(`${__dirname}/contextify.js`).wrap('(function(require, host) { ', '\n})')._compileVM(), sb: loadScript(`${__dirname}/sandbox.js`).wrap('(function (vm, host, Contextify, Decontextify, Buffer) { ', '\n})')._compileVM(), - exp: new VMScript('({exports: {}})')._compileVM() + exp: new VMScript('({exports: {}})')._compileVM(), + runTimeout: new VMScript('fn()', 'timeout_bridge.js')._compileVM() }; +const TIMEOUT_CONTEXT = {context: null}; + +function doWithTimeout(fn, timeout) { + if (!TIMEOUT_CONTEXT.context) { + TIMEOUT_CONTEXT.context = vm.createContext(); + } + TIMEOUT_CONTEXT.context.fn = fn; + try { + return SCRIPT_CACHE.runTimeout._compiledVM.runInContext(TIMEOUT_CONTEXT.context, { + filename: SCRIPT_CACHE.runTimeout.filename, + displayErrors: false, + timeout + }); + } finally { + TIMEOUT_CONTEXT.context.fn = null; + } +} + /** * Class VM. * @@ -227,10 +260,7 @@ class VM extends EventEmitter { }); Reflect.defineProperty(this, '_internal', { - value: SCRIPT_CACHE.cf._compiledVM.runInContext(this._context, { - filename: SCRIPT_CACHE.cf.filename, - displayErrors: false - }).call(this._context, require, host) + value: SCRIPT_CACHE.cf._runInVM(this._context).call(this._context, require, host) }); // prepare global sandbox @@ -292,15 +322,21 @@ class VM extends EventEmitter { const script = code instanceof VMScript ? code : new VMScript(code); script._compileVM(); - try { - return this._internal.Decontextify.value(script._compiledVM.runInContext(this._context, { - filename: script.filename, - displayErrors: false, - timeout: this.options.timeout - })); - } catch (e) { - throw this._internal.Decontextify.value(e); + if (!this.options.timeout) { + try { + return this._internal.Decontextify.value(script._runInVM(this._context)); + } catch (e) { + throw this._internal.Decontextify.value(e); + } } + + return doWithTimeout(()=>{ + try { + return this._internal.Decontextify.value(script._runInVM(this._context)); + } catch (e) { + throw this._internal.Decontextify.value(e); + } + }, this.options.timeout); } } @@ -390,16 +426,10 @@ class NodeVM extends EventEmitter { }); Object.defineProperty(this, '_internal', { - value: SCRIPT_CACHE.cf._compiledVM.runInContext(this._context, { - filename: SCRIPT_CACHE.cf.filename, - displayErrors: false - }).call(this._context, require, host) + value: SCRIPT_CACHE.cf._runInVM(this._context).call(this._context, require, host) }); - const closure = SCRIPT_CACHE.sb._compiledVM.runInContext(this._context, { - filename: SCRIPT_CACHE.sb.filename, - displayErrors: false - }); + const closure = SCRIPT_CACHE.sb._runInVM(this._context); Object.defineProperty(this, '_prepareRequire', { value: closure.call(this._context, this, host, this._internal.Contextify, this._internal.Decontextify, this._internal.Buffer) @@ -510,18 +540,13 @@ class NodeVM extends EventEmitter { dirname = null; } - const module = SCRIPT_CACHE.exp._compiledVM.runInContext(this._context, { - displayErrors: false - }); + const module = SCRIPT_CACHE.exp._runInVM(this._context); const script = code instanceof VMScript ? code : new VMScript(code, filename); script._compileNodeVM(); try { - const closure = script._compiledNodeVM.runInContext(this._context, { - filename: script.filename, - displayErrors: false - }); + const closure = script._runInNodeVM(this._context); returned = closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname); } catch (e) {