-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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: references to context inside objects are not === the original context #855
Comments
Shouldn't vm.runInContext('var result = document.defaultView === this'); be vm.runInContext('var result = document.defaultView === this', sandbox); ? |
@mscdex looks like it. The code throws without that fix. With the fix the assertion still fails. |
Correct me if I'm wrong but isn't that because of the global proxy object? I bet that if you start iojs with |
@mscdex yes, edited OP. @bnoordhuis interesting. You are right that this doesn't work with contextify. Which at least implies there is a workaround with jsdom---namely, do whatever it was that we did with contextify, which apparently was at least slightly different from what we're doing with vm. And you are also right this is due to the global proxy. So at least this is not a regression. However, in browser environments the global proxy is purposefully indistinguishable from the global. (That is, you can never get ahold of the global directly). I wonder if we want to enforce something similar for vm code. Or maybe we don't, since this alternative is more powerful? |
I still don't fully understand what's going on here. Consider this modified test case: var assert = require('assert');
var vm = require('vm');
var sandbox = {};
sandbox.document = { defaultView: sandbox };
sandbox.window = sandbox;
vm.createContext(sandbox);
vm.runInContext('var result1 = document.defaultView === this', sandbox);
vm.runInContext('var result2 = window === this', sandbox);
console.log(sandbox.result1); // false
console.log(sandbox.result2); // true Why does it fail only when stored as a property of another object? |
I think it must be because of these lines: Local<Object> sandbox = PersistentToLocal(isolate, ctx->sandbox_);
Local<Value> rv = sandbox->GetRealNamedProperty(property);
if (rv.IsEmpty()) {
Local<Object> proxy_global = PersistentToLocal(isolate,
ctx->proxy_global_);
rv = proxy_global->GetRealNamedProperty(property);
}
if (!rv.IsEmpty() && rv == ctx->sandbox_) {
rv = PersistentToLocal(isolate, ctx->proxy_global_);
} It seems like in the case of |
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
I think there are two possible things we could do here:
|
1 looks fine to me. I don't think that var sandbox = {};
sandbox.document = { };
vm.createContext(sandbox);
vm.runInContext('document.defaultView === this', sandbox); to create references to global proxy. |
I would really like to investigate removing the global proxy concept if we can, since we shouldn't need it since we're not a browser of multiple interacting iframes. I'll see what I can do. An alternative, if we stick with 1, is we should probably expose a method to re-target the global proxy at another backing global. |
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
See nodejs/node#855 for some discussion of how the "proxy global" gets confusing in vm contexts. We more explicitly handle the separation here, trying to ensure that only the proxy global is observable. At the same time, we move all properties of the window to its instance. Per https://heycam.github.io/webidl/#Global this is actually more correct. But it was also pretty hard to get any passing tests without doing this, because proxy globals are pretty wonky, especially when they interact with prototypes of the original global. (My best guess is that this comes down to how V8's proxy global does not really have correct ES proxy semantics.)
@domenic ... and also this one? |
This is almost certainly not fixed in next. It is going to be a big change, but I am excited to work on it. |
@domenic Is this something you're still excited to work on? Or would adding a |
@Trott yes, but also yes :). No time... |
Since the workaround fixes the /cc @domenic |
@fhinkel I think the issue identified here is still real, and the alternatives I gave in #855 (comment) are the still the best paths forward, in my opinion. The === problem (which is a result of the global/global proxy distinction) is still likely to bite people, especially given the half-assed censorship we do in some cases (illustrated by #855 (comment)). |
OK, thanks for clarifying! |
Fixes nodejs#855 Fixes nodejs#31658 Fixes nodejs#31808
Failing test case:
Investigating this in my local build ... this is the only remaining test suite failure after switching jsdom to io.js vm.
The text was updated successfully, but these errors were encountered: