Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm.runInThisContext is bound to the top context #14757

Closed
TimothyGu opened this issue Aug 11, 2017 · 5 comments
Closed

vm.runInThisContext is bound to the top context #14757

TimothyGu opened this issue Aug 11, 2017 · 5 comments
Labels
help wanted Issues that need assistance from volunteers or PRs that need help to proceed. stalled Issues and PRs that are stalled. vm Issues and PRs related to the vm subsystem.

Comments

@TimothyGu
Copy link
Member

  • Version: 8.3.0
  • Platform: Linux 4.9.0-3-amd64 SMP Debian 4.9.30-2+deb9u3 (2017-08-06) x86_64 GNU/Linux
  • Subsystem: vm
'use strict';

const vm = require('vm');
const context = vm.createContext({
  status: 'inside',
  runInThisContext: vm.runInThisContext
});
global.status = 'outside';
console.log('runInContext only:', vm.runInContext('status', context));
console.log('runInContext + runInThisContext:', vm.runInContext('runInThisContext("status")', context));

prints

runInContext only: inside
runInContext + runInThisContext: outside

suggesting that vm.runInThisContext always runs the code in the top context rather than the current context.

@addaleax addaleax added the vm Issues and PRs related to the vm subsystem. label Aug 11, 2017
@bnoordhuis
Copy link
Member

Lightly tested but this patch should fix it.

EvalMachine() calls v8::UnboundScript::BindToCurrentContext(), which is the context of vm.runInThisContext(), not the most recently entered context.

diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 792b1c4f80..931e3ee824 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -643,6 +643,10 @@ class ContextifyScript : public BaseObject {
     bool display_errors = maybe_display_errors.ToChecked();
     bool break_on_sigint = maybe_break_on_sigint.ToChecked();
 
+    auto context = args.GetIsolate()->GetEnteredContext();
+    if (context.IsEmpty()) context = env->context();
+    Context::Scope context_scope(context);
+
     // Do the eval within this context
     EvalMachine(env, timeout, display_errors, break_on_sigint, args,
                 &try_catch);

@TimothyGu
Copy link
Member Author

@bnoordhuis That does fix the OP, but not this one:

'use strict';
const vm = require('vm');
const context = vm.createContext({
  status: 'inside',
  runInThisContext: vm.runInThisContext
});
global.status = 'outside';

console.log(vm.runInContext('eval', context)("runInThisContext('status')"));

Is it possible to actually fix this?

@TimothyGu
Copy link
Member Author

I think #14757 (comment) is helpful, even if it does not completely fix the problem. @bnoordhuis are you interested in submitting it as a PR?

@bnoordhuis
Copy link
Member

There is good news and bad news. The good news is that the patch fixes not just the original bug report but also the known_issues test for #7788 and a stdio redirection bug in the REPL.

The bad news is that #14757 (comment) is a special case of this, which makes it a regression of the two steps forward, one step back variety.

// Refs: https://github.com/nodejs/node/issues/14757
'use strict';
const common = require('../common');
const assert = require('assert');
const vm = require('vm');

{
  const s = '(function() { return [this, runInThisContext("this")] })';
  const f = vm.runInNewContext(s, vm);
  const [that0, that1] = f();
  assert.strictEqual(that0, that1);
  assert.notEqual(that0, global);
}

I think it could be solved if you knew what context the caller of vm.runInThisContext() belongs to but that's currently pretty much impossible to find out (except for v8::FunctionCallbackInfo<v8::Value>::Callee(), but that's deprecated.)

V8 had an API at one time to retrieve the v8::Function associated with a stack frame (v8::StackFrame::GetFunction(), IIRC.) Perhaps it's time to bring that back.

Alternatively, we could store the script ids of each context and map them back with v8::StackFrame::GetScriptId().

bnoordhuis added a commit to bnoordhuis/io.js that referenced this issue Oct 6, 2017
Change `vm.runInThisContext()` to use the last entered context, not the
top-level context that `vm.runInThisContext()` belongs to.

Note the call chain:

    1. `node::ContextifyScript::RunInThisContext()`
    2. `node::ContextifyScript::EvalMachine()`
    3. `v8::Script::BindToCurrentContext()`

The current context in `RunInThisContext()` is that of the top-level
context which was then bound to the script to execute.

It works when `vm.runInThisContext()` is called from the top-level
context (the common case and hence why this bug went unnoticed for
so long) but not when called from an inferior context.

As a pleasant side effect, this commit fixes a bug in the REPL where
writes to `process.stdout` and `process.stderr` still went to the real
stdout and stderr instead of being captured redirected.

Fixes previously failing test `known_issues/test-repl-require-context`
which has been moved to `test/parallel` and renamed to avoid a conflict
with an existing test of the same name.

Note that this commit changes the behavior of the following snippet:

    const s = '(function() { return vm.runInThisContext(this) })()';
    const f = vm.runInNewContext(s, vm);
    f();

Before this commit, it returned the |this| of the new context, now
it returns the |this| of the enclosing context.  Two steps forward,
one step back.

Fixes: nodejs#7788
Refs: nodejs#14757
@targos targos added the stalled Issues and PRs that are stalled. label Nov 4, 2018
@jasnell jasnell added the help wanted Issues that need assistance from volunteers or PRs that need help to proceed. label Jun 26, 2020
@github-actions
Copy link
Contributor

Closing this because it has stalled. Feel free to reopen if this issue is still relevant, or to ping the collaborator who labelled it stalled if you have any questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Issues that need assistance from volunteers or PRs that need help to proceed. stalled Issues and PRs that are stalled. vm Issues and PRs related to the vm subsystem.
Projects
None yet
Development

No branches or pull requests

5 participants