Skip to content
Prev Previous commit
Next Next commit
auto attachment from runInContext
Not recommended for multiple runs on the same context.
  • Loading branch information
TimothyGu committed Jul 17, 2017
commit fc7d4085bba9ce4a7a9defd038ff168f4854143f
29 changes: 24 additions & 5 deletions lib/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@

const binding = process.binding('contextify');
const Script = binding.ContextifyScript;
const { contextAttached, attachContext, detachContext } = (() => {
try {
return require('inspector');
} catch (err) {
return {};
}
})();

// The binding provides a few useful primitives:
// - Script(code, { filename = "evalmachine.anonymous",
Expand All @@ -46,11 +53,23 @@ Script.prototype.runInThisContext = function(options) {
};

Script.prototype.runInContext = function(contextifiedSandbox, options) {
if (options && options.breakOnSigint && process._events.SIGINT) {
return sigintHandlersWrap(realRunInContext, this,
[contextifiedSandbox, options]);
} else {
return realRunInContext.call(this, contextifiedSandbox, options);
const needToAttach = contextAttached &&
!(options && options.doNotInformInspector) &&
!contextAttached(contextifiedSandbox);
if (needToAttach) {
attachContext(contextifiedSandbox);
}
try {
if (options && options.breakOnSigint && process._events.SIGINT) {
return sigintHandlersWrap(realRunInContext, this,
[contextifiedSandbox, options]);
} else {
return realRunInContext.call(this, contextifiedSandbox, options);
}
} finally {
if (needToAttach) {
detachContext(contextifiedSandbox);
}
}
};

Expand Down
89 changes: 88 additions & 1 deletion test/inspector/test-inspector-contexts-js.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
contextAttached
} = require('inspector');
const { promisify } = require('util');
const { createContext } = require('vm');
const { createContext, runInContext } = require('vm');

common.crashOnUnhandledRejection();

Expand Down Expand Up @@ -97,6 +97,43 @@ async function main() {
await eventPromise;
assert.strictEqual(contextAttached(sandbox), false);
}

// Re-attaching contextified sandbox.
{
const VM_CONTEXT_NAME = 'New VM Context';
const VM_CONTEXT_ORIGIN = 'https://nodejs.org/api/vm.html';

const eventPromise = fires(once('Runtime.executionContextCreated'));
attachContext(sandbox, {
name: VM_CONTEXT_NAME,
origin: VM_CONTEXT_ORIGIN
});
vmContext = (await eventPromise).params.context;
assert.strictEqual(vmContext.name, VM_CONTEXT_NAME);
assert.strictEqual(vmContext.origin, VM_CONTEXT_ORIGIN);
assert.strictEqual(vmContext.auxData.isDefault, false);
assert.strictEqual(contextAttached(sandbox), true);
}

// Evaluating expressions in the specified context.
{
const { result } = await post('Runtime.evaluate', {
expression: 'propInSandbox++',
contextId: vmContext.id
});
assert.strictEqual(result.type, 'number');
assert.strictEqual(result.value, 43);
assert.strictEqual(sandbox.propInSandbox, 44);
}

// Detach context.
{
const eventPromise = fires(once('Runtime.executionContextDestroyed'));
detachContext(sandbox);
const destroyedId = (await eventPromise).params.executionContextId;
assert.strictEqual(destroyedId, vmContext.id);
assert.strictEqual(contextAttached(sandbox), false);
}
}

// Default context names.
Expand Down Expand Up @@ -124,6 +161,56 @@ async function main() {
}
}

// Automatic attachment from vm.runInContext.
{
const sandbox = {
propInSandbox: 42
};
createContext(sandbox);
{
const createdPromise = fires(once('Runtime.executionContextCreated'));
const destroyedPromise = fires(once('Runtime.executionContextDestroyed'));
const result = runInContext('propInSandbox++', sandbox);
assert.strictEqual(result, 42);
assert.strictEqual(sandbox.propInSandbox, 43);
await createdPromise;
await destroyedPromise;
assert.strictEqual(contextAttached(sandbox), false);
}

// doNotInformInspector
{
const createdPromise =
neverFires(once('Runteme.executionContextCreated'));
const destroyedPromise =
neverFires(once('Runtime.executionContextDestroyed'));
const result = runInContext('propInSandbox++', sandbox, {
doNotInformInspector: true
});
assert.strictEqual(result, 43);
assert.strictEqual(sandbox.propInSandbox, 44);
await createdPromise;
await destroyedPromise;
assert.strictEqual(contextAttached(sandbox), false);
}

// Do not try to attach or detach when sandbox is already attached.
attachContext(sandbox);
{
const createdPromise =
neverFires(once('Runtime.executionContextCreated'));
const destroyedPromise =
neverFires(once('Runtime.executionContextDestroyed'));
const result = runInContext('propInSandbox++', sandbox);
assert.strictEqual(result, 44);
assert.strictEqual(sandbox.propInSandbox, 45);
await createdPromise;
await destroyedPromise;
assert.strictEqual(contextAttached(sandbox), true);
}
detachContext(sandbox);
}

session.disconnect();
}

Expand Down