-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Normative: Add three missing checks in proxy internal methods #666
Conversation
Is this in regards to #652? |
@bterlson Yes, forgot to mention it. |
Testcase against [[GetOwnProperty]]: a property reported as nonwritable, nonconfigurable must not change its value. var target = Object.seal({x: 2})
var proxy = new Proxy(target, {
getOwnPropertyDescriptor(o, p) {
var desc = Reflect.getOwnPropertyDescriptor(o, p)
if (desc && 'writable' in desc)
desc.writable = false
return desc
}
})
Object.getOwnPropertyDescriptor(proxy, 'x') // !!! should throw
// { value: 2, configurable: false, writable: false }
Object.defineProperty(proxy, 'x', { value: 3 })
Object.getOwnPropertyDescriptor(proxy, 'x') // { value: 3 } Testcase against [[DefineProperty]]: a property defined as nonwritable, nonconfigurable must not change its value. var target = Object.seal({x: 2})
var proxy = new Proxy(target, {
defineProperty(o, p, desc) {
delete desc.writable
return Reflect.defineProperty(o, p, desc)
}
})
Object.defineProperty(proxy, 'x', { value: 2, configurable: false, writable: false })
// !!! should throw
proxy.x = 3
Object.getOwnPropertyDescriptor(proxy, 'x') // { value: 3 } Testcase against [[Delete]]: a successfuly deleted property on a nonextensible object must not reappear. var target = Object.preventExtensions({ x: 1 })
var proxy = new Proxy(target, {
deleteProperty() { return true }
})
Object.isExtensible(proxy) // false
delete proxy.x // true !!! should throw
proxy.hasOwnProperty('x') // true |
There is an issue (unrelated to invariants of essential methods) in proxy's [[OwnPropertyKeys]] method in case the target object's [[OwnPropertyKeys]] produces duplicate keys, see message on es-discuss. But that is better resolved by #461 (comment) (forbid [[OwnPropertyKeys]] returning duplicate keys). |
Finally there are issues with a strong interpretation of the Invariants of the essential internal methods in edge cases, see this thread on es-discuss. In case we want to resolve that, we need to:
|
This feels like "needs consensus", as it will cause slowdowns and such... |
Definitely needs-consensus. Also I wonder if we should package all of the proxy invariant fixes into a single PR? Removing duplicate keys for example would have some other effects (such as being able to revert 6d0fc45). |
+1 on needs consensus. I am willing to lead but have asked Claude and Tom On Fri, Aug 12, 2016 at 11:23 AM, Brian Terlson notifications@github.com
Cheers, |
In the present PR, I have purposely included only the three missing checks, because they are real bugs that should not need much discussion and should IMHO be corrected rapidly. |
I have reviewed Claude’s changes in this PR and they appear to resolve the three outstanding issues as discussed on esdiscuss. I agree with Claude that it would be better to treat this issue separately from other, partially related discussions. This PR addresses missing proxy invariant checks that I consider to be a bug in the original Proxy spec. |
I would be fine pulling in just these additional invariants, but let me wait until tomorrow in case there are objections. Any volunteers to write tests? |
cc @verwaest |
I'm trying to get a review of this from the people who implemented Proxies in V8. Can we hold off on merging this for a little bit until we can hear back from them? |
How confident are we that these three additions are sufficient to fix the bug (and don't introduce other problems)? There exist several implementations of the current spec, buggy though it may be, and it's slightly concerning to change the spec in such a way that it matches no implementations. Given that there's a plan to add more checks here it seems reasonable to ask for more feedback before merging (most naturally by consensus). |
We certainly do not have consensus at the present time. This must not be merged until we do. |
…proxy invariant checks in getOwnPropertyDescriptor, defineProperty and deleteProperty
FWIW, I added the proposed missing proxy invariant checks to my harmony-reflect shim, and using Claude's test-cases confirmed that all three cases now throw an appropriate TypeError. The changes do not impact the results of any of my other tests, which is good. Harmony-reflect is obviously not a proper engine implementation, but it does aim to faithfully self-host the Proxy spec in JS. The changes I had to make follow the exact same pattern of the pre-existing invariant checks. This provides some evidence that these new invariant checks should not be problematic, given the overhead already imposed by pre-existing invariant checks. |
If you are interested in a formal proof, see: https://github.com/claudepache/es-invariants (WIP) |
Did tests ever land for this? /cc @leobalter @tcare. |
After the september TC39 meeting I promised to write up some test262 tests, but I never got around to it. If this is still a blocking issue, I'll see if I can at least contribute Claude's test cases from this thread. |
@tvcutsem it is blocking, yes. Let me know if you need help with the porting effort. |
Contributing test262 tests for these changes has been on my todo list for way too long and other priorities keep on interfering. Part of the reason is I'm not familiar enough with test262 guidelines. Anyone willing to port Claude's test cases above #666 (comment) to test262? Apologies for slacking off. |
How is this effort going? Has anyone written tests for this change? |
spec.html
Outdated
@@ -8467,6 +8469,9 @@ <h1>[[GetOwnProperty]] (_P_)</h1> | |||
<li> | |||
A property cannot be reported as non-configurable, if it does not exist as an own property of the target object or if it exists as a configurable own property of the target object. | |||
</li> | |||
<li> | |||
A property cannot be reported as both non-configurable and non-writable, unless it exists as a non-configurable, non-writable own property of the target object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence uses “unless it exists as an X own”, while the others in this section use “if it does not exist as an own, or if it exists as an X own” - i like your wording better, so maybe we should update them all to use this form? That’s also fine to do in a followup, but in that case, this should probably follow the form of the others in the interim?
I'd like to suggest that we don't land this patch until we have implementation experience (ideally multiple). Would it make sense to include a label for this state, like "awaiting implementation feedback"? |
For reference, the tests:
I suppose we could create a label; are there other PRs that would fall into that category? |
@ljharb If it helps, we can also use a feature tag in Test262 to keep track of these tests without listing each one separately. |
I think I am going to try this in SpiderMonkey. Firefox actually uses quite a few proxies, so it might be interesting to see what a complete test run uncovers. |
@leobalter sure, any way for people reading this PR to quickly see the actual implementation status is great :-) |
This change has been in Firefox Nightly for about a week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps phrasing should be made more consistent along the lines @ljharb suggests. I'll leave that for others.
As for technical content, all looks good. I approve.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
92f0555
to
eb79f07
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one final callout - I've reworded these three comments so they're using similar "unless" phrasing. Any objections before this is merged?
spec.html
Outdated
</li> | ||
<li> | ||
A property cannot be reported as non-configurable, if it does not exist as an own property of the target object or if it exists as a configurable own property of the target object. | ||
A property cannot be reported as both non-configurable and non-writable, unless it exists as a non-configurable, non-writable own property of the target object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've reworded this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This phrase is correct and corresponds to the added check.
spec.html
Outdated
</li> | ||
<li> | ||
A property cannot be reported as existent, if it does not exist as an own property of the target object and the target object is not extensible. | ||
A property cannot be reported as non-configurable, unless it exists as a non-configurable own property of the target object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've reworded this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub does not show the reworded phrase in regard to the old one, so it confused me at first. Therefore I confirm that:
The new phrase just before that one (in source text order, L.8988) is logically equivalent to the one shown at left. (L.8986)
This phrase (L.8991) is a correct rewording of the next one (L.8989)
spec.html
Outdated
@@ -8980,13 +8982,16 @@ <h1>[[GetOwnProperty]] ( _P_ )</h1> | |||
A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object. | |||
</li> | |||
<li> | |||
A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible. | |||
A property cannot be reported as non-existent, if the target object is not extensible, unless it does not exist as an own property of the target object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've reworded this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rewording is logically correct, but it makes me more difficult to parse: two dependant clauses: “if... unless”; double negation: “unless ... not...”.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@claudepache what about:
A property cannot be reported as non-existent, if the target object is not extensible, unless it does not exist as an own property of the target object. | |
A property cannot be reported as non-existent, unless either the target object is extensible, or it does not exist as an own property of the target object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s logically correct. But I’m not convinced that the rewording adds clarity. (In any case, this is not a blocker, since it is just an informative note.)
https://bugs.webkit.org/show_bug.cgi?id=198630 Patch by Alexey Shvayka <shvaikalesh@gmail.com> on 2019-07-24 Reviewed by Darin Adler. JSTests: * stress/proxy-delete.js: Assert isExtensible is called in correct order. * test262/expectations.yaml: Mark 6 test cases as passing. Source/JavaScriptCore: Add three missing checks in Proxy internal methods. These checks are necessary to maintain the invariants of the essential internal methods. (tc39/ecma262#666) 1. [[GetOwnProperty]] shouldn't return non-configurable and non-writable descriptor when the target's property is writable. 2. [[Delete]] should return `false` when the target has property and is not extensible. 3. [[DefineOwnProperty]] should return `true` for a non-writable input descriptor when the target's property is non-configurable and writable. Shipping in SpiderMonkey since https://hg.mozilla.org/integration/autoland/rev/3a06bc818bc4 (version 69) Shipping in V8 since https://chromium.googlesource.com/v8/v8.git/+/e846ad9fa5109428be50b1989314e0e4e7267919 * runtime/ProxyObject.cpp: (JSC::ProxyObject::performInternalMethodGetOwnProperty): Add writability check. (JSC::ProxyObject::performDelete): Add extensibility check. (JSC::ProxyObject::performDefineOwnProperty): Add writability check. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@247811 268f45cc-cd09-0410-ab3c-d52691b4dbfc
spec.html
Outdated
@@ -8968,6 +8968,8 @@ <h1>[[GetOwnProperty]] ( _P_ )</h1> | |||
1. If _resultDesc_.[[Configurable]] is *false*, then | |||
1. If _targetDesc_ is *undefined* or _targetDesc_.[[Configurable]] is *true*, then | |||
1. Throw a *TypeError* exception. | |||
1. If _resultDesc_ has a [[Writable]] field and _resultDesc_.[[Writable]] is *false*, then | |||
1. If _targetDesc_.[[Writable]] is *true*, throw a *TypeError* exception. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have an "if" inside another "if"? Just combine the conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generally its just about making it easier to understand the logic for readers. the outer one contains invariants of the resultDesc and the inner one contains invariants of the targetDesc.
I'm curious why this is still not merged. Is there still something that needs to be done? Thanks. |
@raulsebastianmihaila yes; waiting for a reply on #666 (comment) from @claudepache primarily. |
eb79f07
to
b41a832
Compare
What's the current implementation status of this change? Is it shipping in Firefox, @evilpie ? |
Judging by the tests in #666 (comment), V8 implements the 3 checks. |
Per the test262.report links in #666 (comment), every reported engine but Chakra currently implements this PR. |
https://bugs.webkit.org/show_bug.cgi?id=198630 Patch by Alexey Shvayka <shvaikalesh@gmail.com> on 2019-07-24 Reviewed by Darin Adler. JSTests: * stress/proxy-delete.js: Assert isExtensible is called in correct order. * test262/expectations.yaml: Mark 6 test cases as passing. Source/JavaScriptCore: Add three missing checks in Proxy internal methods. These checks are necessary to maintain the invariants of the essential internal methods. (tc39/ecma262#666) 1. [[GetOwnProperty]] shouldn't return non-configurable and non-writable descriptor when the target's property is writable. 2. [[Delete]] should return `false` when the target has property and is not extensible. 3. [[DefineOwnProperty]] should return `true` for a non-writable input descriptor when the target's property is non-configurable and writable. Shipping in SpiderMonkey since https://hg.mozilla.org/integration/autoland/rev/3a06bc818bc4 (version 69) Shipping in V8 since https://chromium.googlesource.com/v8/v8.git/+/e846ad9fa5109428be50b1989314e0e4e7267919 * runtime/ProxyObject.cpp: (JSC::ProxyObject::performInternalMethodGetOwnProperty): Add writability check. (JSC::ProxyObject::performDelete): Add extensibility check. (JSC::ProxyObject::performDefineOwnProperty): Add writability check. Canonical link: https://commits.webkit.org/213935@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247811 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Those checks are needed in order to maintain the Invariants of the essential internal methods. Their omission is a bug in the spec. This is a minimal patch for resolving them.
It remains glitches in some weird edge cases (commented below), but they need a little more refactoring.
/cc @erights, @tvcutsem
Fixes #652