Open caridy opened 8 years ago
Hi @caridy , what vectors are you concerned about? What is the issue with freshGlobals
? In what way does it make speccing easier?
Honestly I'm completely fine with only allowing strict mode anyway. In fact I was under the impression that was already the case.
The polyfill only allows strict mode because it relies on being able to statically determine a conservative bound on scoping. The README.md text says only
At this time, to maximize compatibility with normal ECMAScript, we do not alter an immutable root realm's evaluators to evaluate code in strict mode by default. However, we should consider doing so. Most of the code, including legacy code, that one would wish to run under an immutable root realm is probably already compatible with strict mode. Omitting sloppy mode from immutable root realms and their spawned descendants would also make sections B.1.1, B.1.2, B.3.2, B.3.3, and B.3.4 non issues. It is unclear what an immutable root realm's evaluators should specify regarding the remaining normative optional syntax in section B.1. But the syntax accepted by these evaluators, at least in strict mode, should probably be pinned down precisely by the spec.
@erights is anyone actually interested in running non-strict code in spawned frozen realms?
Having read some of your publications on the subject, I'm also not sure how the security proof would look like for non-strict code (quite possibly you proved it and I missed it).
Anyway, I definitely think that given modules are always strict, classes are always strict and so on - time is better invested in strict mode. Sloppy mode support for can always be added later.
@erights is anyone actually interested in running non-strict code in spawned frozen realms?
I doubt it.
Having read some of your publications on the subject, I'm also not sure how the security proof would look like for non-strict code (quite possibly you proved it and I missed it).
I have not actually proved anything yet :(. However, thanks for asking this --- it prodded me into realizing a potential conflict between sloppy mode and frozen realms:
In ES5 we were careful to poison strict .caller, .callee, and .arguments. In ES2015 we refactored some of the poisoning into methods inherited from Function.prototype and extended it to cover an unfortunate oversight in ES5: we poisoned builtin functions too. Neither ES5 nor ES2015 poisoned sloppy functions since that is where the de facto legacy non-local causality behavior needed to be preserved. Obviously, if frozen realms do admit sloppy functions, then those would need to be poisoned as well, or at least not provide the de facto legacy non-local causality behavior. This is all clear.
The conflict I missed: In ES5 we also specified that aSloppyFunction.caller could not reveal a strict caller. In ES2015 we specified that it could not reveal a non-sloppy caller. IOW, we repaired the same ES5 oversight, covering builtins as well. (Someone, please check this.) However, if we admit sloppy functions into frozen realms, even if they themselves are poisoned, we need to extend the above prohibition so that aSloppyFunction.caller from a non-frozen-realm sloppy function also cannot reveal a sloppy function from a frozen realm.
This additional prohibition would require a new mechanism. Prior history of trying to get engine makers to implement such constraints does not fill me with confidence that this additional prohibition would be honored quickly. OTOH, a strict-only restriction is something I am confident we could get reliably. I think this issue is fatal enough for the prospect of allowing sloppy functions into frozen realms. Thus, I now agree that frozen realms should be strict only. If there is no objection, I will close this issue as soon as spec text is updated.
Anyway, I definitely think that given modules are always strict, classes are always strict and so on - time is better invested in strict mode.
Agreed.
Sloppy mode support for can always be added later.
Only if the above .caller problem were fixed, both in the spec and, with confidence, in actual implementations. If there's no objection, let's just forget this option -- taking sloppy functions off the table completely for frozen realms.
@erights I will update the spec text to reflect the consensus here for frozen realms. Let's keep this issue open so I can commit against it to preserve historical discussions.
As for the cases I'm worry about, I will elaborate more to try to make the case against non-strict spawned realms in general:
const childRealm = someRealm.spawn();
childRealm.eval(`
foo = function () {...}
this.foo === undefined; // where "this" is childRealm.[[FreshObject]].
`);
If the spawn realm is really lightweight (not a real realm, but some sort of shim of an existing one), and it doesn't need to have an environment record associated to it, just an ordinary freshGlobal
object, foo
will be defined in the environment record associated to someRealm
. In the other hand, if we force the evaluation process to be strict, we force them to do something like:
const childRealm = someRealm.spawn({
bar: {}
});
childRealm.eval(`
this.foo = function () {...}
// or
bar.foo = function () {...}
`);
where the value of this
, or the mutable global bar
, is controlled by the childRealm
via its freshGlobal
object.
update: this is obviously a problem only if freshGlobal
is an ordinary object to make the spawned realm very lightweight, but if we choose to create it via NewGlobalEnvironment, then this is not really a problem.
Further investigation suggested that, at minimum, the lightweight aspect of the spawned realm is questionable. It seems that, aside from the 3 objects required for it (eval
, Function
and freshGlobal
), an internal slot called [[Environment]]
is needed to store the result of performing NewGlobalEnvironment(freshGlobal, freshGlobal)`, as this is needed when invoking any of the runtime semantics to evaluate new code.
Although, I don't think [[Environment]]
and its corresponding Environment Record is very expensive, but we should keep that in mind going forward, unless we find an alternative way of evaluating code without this artifact.
Yes, I think an [[Environment]]
slot is needs to store the result of performing NewGlobalEnvironment(freshGlobal, freshGlobal)
. I just read the spec at that link. This does not add allocation of any user-visible objects. It does add an addition 5 spec-level objects, i.e., objects that are explanatory devices for the specified semantics.
Assuming these corresponds one-for-one with internal implementation allocations, this brings the total to 9 (or 13 with the Date and Math override). This still deserves the term "lightweight".
Am I missing additional implied allocations?
I have the same impression, I will go ahead and spec all this! thanks @erights.
@erights got the spec text updated in 8f21259f6581edddeb1aa5752c8444dbf5b4e06d, here is the html version: https://rawgit.com/FUDCo/frozen-realms/master/index.html
Few notes about this update:
const s = someRealm.spawn()
.const realm = s.realm
.eval()
, and the fresh global object is the getter global
. Other notes:
We haven't get to answer the original question, whether or not spawned realms should be strict, but at least we have some progress.
I know @erights has some concerns about reducing the capabilities of the spawned realms, but I wonder if this is a decent compromise, at least for frozen realms which are already crippled by their inability to polyfill any primordial or poisoning the parent realm. It seems that preventing sloppy mode we can eliminate all vectors that could cause a new binding to be created in parent realm, forcing globals to be defined in
freshGlobals
, and this will certainly make it easier to spec :)