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

Normative: Add three missing checks in proxy internal methods #666

Merged
merged 1 commit into from
Jan 6, 2020

Conversation

claudepache
Copy link
Contributor

@claudepache claudepache commented Aug 12, 2016

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

@bterlson
Copy link
Member

Is this in regards to #652?

@claudepache
Copy link
Contributor Author

@bterlson Yes, forgot to mention it.

@bterlson bterlson added normative change Affects behavior required to correctly evaluate some ECMAScript source text needs test262 tests The proposal should specify how to test an implementation. Ideally via github.com/tc39/test262 labels Aug 12, 2016
@claudepache
Copy link
Contributor Author

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

@claudepache
Copy link
Contributor Author

claudepache commented Aug 12, 2016

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).

@claudepache
Copy link
Contributor Author

claudepache commented Aug 12, 2016

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:

  • add invariant checks to ordinary [[Get]], [[Set]] and [[HasProperty]] internal methods, because they can run user code that might do weird things;
  • refactor some invariant checks of proxies (I think, that would essentially result in omitting a few useless calls to the target's internal methods, but that needs to be confirmed).

@domenic
Copy link
Member

domenic commented Aug 12, 2016

This feels like "needs consensus", as it will cause slowdowns and such...

@bterlson
Copy link
Member

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).

@bterlson bterlson added the needs consensus This needs committee consensus before it can be eligible to be merged. label Aug 12, 2016
@erights
Copy link

erights commented Aug 12, 2016

+1 on needs consensus. I am willing to lead but have asked Claude and Tom
to attend by hangout. +1 also on consolidating these issues.

On Fri, Aug 12, 2016 at 11:23 AM, Brian Terlson notifications@github.com
wrote:

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
6d0fc45
).


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#666 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAQtzGj9dFqogyrJbz5Ww-Qq0MJQ-HX3ks5qfLowgaJpZM4JjTK5
.

Cheers,
--MarkM

@claudepache
Copy link
Contributor Author

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.

@tvcutsem
Copy link

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.

@bterlson
Copy link
Member

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?

@littledan
Copy link
Member

cc @verwaest

@littledan
Copy link
Member

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?

@ajklein
Copy link
Contributor

ajklein commented Aug 17, 2016

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).

@erights
Copy link

erights commented Aug 17, 2016

We certainly do not have consensus at the present time. This must not be merged until we do.

tvcutsem pushed a commit to tvcutsem/harmony-reflect that referenced this pull request Aug 17, 2016
…proxy invariant checks in getOwnPropertyDescriptor, defineProperty and deleteProperty
@tvcutsem
Copy link

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.

@claudepache
Copy link
Contributor Author

How confident are we that these three additions are sufficient to fix the bug (and don't introduce other problems)?

If you are interested in a formal proof, see: https://github.com/claudepache/es-invariants (WIP)

@bterlson bterlson removed the needs consensus This needs committee consensus before it can be eligible to be merged. label Nov 29, 2016
@bterlson
Copy link
Member

Did tests ever land for this? /cc @leobalter @tcare.

@tvcutsem
Copy link

tvcutsem commented Dec 4, 2016

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.

@bterlson
Copy link
Member

bterlson commented Dec 5, 2016

@tvcutsem it is blocking, yes. Let me know if you need help with the porting effort.

@raulsebastianmihaila
Copy link

raulsebastianmihaila commented Feb 28, 2017

Looks like these 3 new invariants are only added in section 9.5. They should also be added in section 6.1.7.3.

Edit: Ignore my comment, these invariants are proxy specific.

@tvcutsem
Copy link

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.

@raulsebastianmihaila raulsebastianmihaila mentioned this pull request Jan 6, 2018
@littledan
Copy link
Member

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.
Copy link
Member

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?

@ljharb ljharb requested review from erights and tvcutsem May 3, 2019 17:09
@littledan
Copy link
Member

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"?

@leobalter
Copy link
Member

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.

@evilpie
Copy link
Contributor

evilpie commented May 15, 2019

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.

https://bugzilla.mozilla.org/show_bug.cgi?id=1551939

@ljharb
Copy link
Member

ljharb commented May 15, 2019

@leobalter sure, any way for people reading this PR to quickly see the actual implementation status is great :-)

@evilpie
Copy link
Contributor

evilpie commented Jun 4, 2019

This change has been in Firefox Nightly for about a week.

@ljharb ljharb self-assigned this Jun 26, 2019
Copy link

@erights erights left a 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.

@ljharb

This comment has been minimized.

@claudepache

This comment has been minimized.

@ljharb ljharb force-pushed the proxy-missing-checks branch from 92f0555 to eb79f07 Compare June 27, 2019 06:18
ljharb pushed a commit to claudepache/ecma262 that referenced this pull request Jun 27, 2019
Copy link
Member

@ljharb ljharb left a 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've reworded this

Copy link
Contributor Author

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've reworded this

Copy link
Contributor Author

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've reworded this

Copy link
Contributor Author

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...”.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claudepache what about:

Suggested change
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.

Copy link
Contributor Author

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.)

caiolima pushed a commit to caiolima/webkit that referenced this pull request Jul 25, 2019
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.
Copy link
Member

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.

Copy link
Member

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.

@raulsebastianmihaila
Copy link

I'm curious why this is still not merged. Is there still something that needs to be done? Thanks.

@ljharb
Copy link
Member

ljharb commented Jan 5, 2020

@raulsebastianmihaila yes; waiting for a reply on #666 (comment) from @claudepache primarily.

@ljharb ljharb force-pushed the proxy-missing-checks branch from eb79f07 to b41a832 Compare January 6, 2020 18:57
@ljharb ljharb merged commit b41a832 into tc39:master Jan 6, 2020
@littledan
Copy link
Member

What's the current implementation status of this change? Is it shipping in Firefox, @evilpie ?

@syg
Copy link
Contributor

syg commented Feb 5, 2020

Judging by the tests in #666 (comment), V8 implements the 3 checks.

@ljharb
Copy link
Member

ljharb commented Feb 5, 2020

Per the test262.report links in #666 (comment), every reported engine but Chakra currently implements this PR.

ryanhaddad pushed a commit to WebKit/WebKit that referenced this pull request Dec 22, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has consensus This has committee consensus. has test262 tests normative change Affects behavior required to correctly evaluate some ECMAScript source text
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Should proxies be able to lie wrt freezing?