tc39 / proposal-dynamic-code-brand-checks

TC39 proposal that enables flexible brand checks before dynamic code loading
MIT License
32 stars 5 forks source link

Is there a way that static string literals could dodge the check as well? #2

Closed dead-claudia closed 5 years ago

dead-claudia commented 5 years ago

Literal eval ( "..." ) in source code, where the parameter is an immediate string literal, works mostly the same way as having the code outside eval, just it throws a runtime ReferenceError instead of a static parse-time error and it can run statements in expression contexts. This is useful in certain scripts for safely getting %GeneratorPrototype% and the like in polyfill code, things that are only accessible indirectly via syntax and where the syntax might not necessarily be supported. (Engines could optimize this, but AFAICT they don't.)

Any chance this could be added to the safe list? Intentionally, I'm just suggesting adding simple string literals, not template strings or any dynamic string value, and I'm also not suggesting this should be carried to eval ( "a" + "b" ) or the like, where engines can constant-fold it to a static string literal.

mikesamuel commented 5 years ago

One of the goals for this proposal is to allow something like

eval(TrustedScript`...`)

How much is polyfill writing encumbered by having to do something like

eval(typeof TrustedScript !== 'undefined' ? TrustedScript`...` : '...')

I think your literal model fits with the assumptions behind this, but I just don't know of a simple spec change that would allow that.

How important is it to you that the output of the following expressions be treated as literal when literal is a literal string:

?

dead-claudia commented 5 years ago

It's not especially important to me that any of the dynamic strings are treated as literal, and I'm not even proposing that var str = "foo"; eval(str) should be treated as sufficiently "literal". Just the syntactic form eval ( StringLiteral ) itself. (Implementations that can't dynamically evaluate anything, like XS, could still potentially evaluate this in theory. The semantic difference is that they have to defer the error to runtime.)

mikesamuel commented 5 years ago

Ok. Thanks for explaining.

I think it'll be controversial because of how it affects inlining.

It's already the case that inlining isn't simple.

let x = 'outer';
function f(str) { let x = 'inner', e = eval; return e(str); }
function g(str) { let x = 'inner'; return eval(str); }
f('x') !== g('x')

But in that case, it's possible to statically determine whether the inlining affects semantics. I think closure compiler optimizes f to function f(str) { return (0, eval)(str); }.

But in var str = "foo"; e(str) it's not possible to tell if inlining str preserves semantics where e could alias eval.

I think you could make a strong case that inliners like Babel shouldn't worry about preserving semantics in this situation, and that any change to existing programs would not introduce a CSP bypass.

But if V8 or SpiderMonkey rely on inlining, then it'd probably be DOA since they are super sensitive to semantic violations.

mikesamuel commented 5 years ago

Changing the semantics of eval('...') would not reuse many of the proposed spec changes, would not be complicated AFAICT by the acceptance or rejection of this proposal, and can proceed separately.

Closing as out of scope.