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

Object.prototype should be an immutable prototype exotic object #261

Closed
bterlson opened this issue Feb 4, 2016 · 11 comments
Closed

Object.prototype should be an immutable prototype exotic object #261

bterlson opened this issue Feb 4, 2016 · 11 comments

Comments

@bterlson
Copy link
Contributor

bterlson commented Feb 4, 2016

You should not be able to change its prototype with Object.setPrototypeOf, __proto__, or any other means. See also: tc39/ecma262#308.

@dilijev
Copy link
Contributor

dilijev commented Apr 23, 2016

@bterlson I'm wondering if you can help me understand this bug a bit better with actual/expected behavior?

I've tried the following:

Object.__proto__ // function () {}
Object.prototype // Object {}
Object.setPrototypeOf(Object, {'a': 2})
Object.prototype // Object {} // no change
Object.__proto__ // Object {a: 2} // changed

And this succeeds with the same behavior (modulo differences in printed strings in the interactive console) in both Canary and Edge.

But since my example changed Object.__proto__ and not Object.prototype I get the feeling I'm missing the essence of this issue.

@ljharb
Copy link
Collaborator

ljharb commented Apr 23, 2016

Object.setPrototypeOf(Object.prototype, {}) should fail silently in sloppy mode and throw in strict mode, as should any other mechanism of changing Object.prototype's [[Prototype]].

@dilijev
Copy link
Contributor

dilijev commented Apr 23, 2016

@ljharb Thanks for the clarification. Looking into it further now.

@dilijev
Copy link
Contributor

dilijev commented Apr 23, 2016

@ljharb In sloppy mode, that statement causes the error message Cyclic __proto__ value in both Canary and Edge. I assume this is due to another issue. Is there another possibility that would avoid that error message, or is the goal here to silently fail and not report any error message at all?

@ljharb
Copy link
Collaborator

ljharb commented Apr 23, 2016

Oh sure. Set it to Object.create(null) or a cross-realm value instead, my mistake.

@bterlson
Copy link
Contributor Author

Just to be clear, here's a code sample:

var obj = Object.create(null);
Object.setPrototypeOf(Object.prototype, obj);
// or...
Object.prototype.__proto__ = obj;

Expected: TypeError in all modes
Actual: No TypeError

Do note that the type error is not dependent on mode (can you confirm @ljharb?).

@ljharb
Copy link
Collaborator

ljharb commented Apr 25, 2016

Confirmed - in both https://tc39.github.io/ecma262/#sec-object.setprototypeof and https://tc39.github.io/ecma262/#sec-set-object.prototype.__proto__ step 4 will return false, and step 5 should throw a TypeError.

(It's unfortunate that the [[SetPrototypeOf]] method doesn't point to https://tc39.github.io/ecma262/#sec-immutable-prototype-exotic-objects but that's where step 4 returns false)

@dilijev
Copy link
Contributor

dilijev commented Apr 25, 2016

Thanks @bterlson and @ljharb. I think I understand the requirements much better now.

Earlier @ljharb had said:

should fail silently in sloppy mode and throw in strict mode

And @bterlson said:

Expected: TypeError in all modes

Is it that TypeError is not thrown in sloppy mode in general, or was one of these statements in error?

@bterlson
Copy link
Contributor Author

I believe @ljharb was mistaken - it should be a TypeError in all modes. He confirms this in his most recent comment.

@ljharb
Copy link
Collaborator

ljharb commented Apr 26, 2016

@dilijev yes, my mistake. mode is irrelevant here (i thought it mattered for __proto__ assignment, but i'm wrong)

@dilijev
Copy link
Contributor

dilijev commented Apr 26, 2016

Okay, thanks for your patience in bringing me up to speed, here. :)

dilijev added a commit to dilijev/ChakraCore that referenced this issue Apr 27, 2016
This means that any attempts to set the [[Prototype]] slot of the Object Prototype Object (the object which is initially pointed to by Object.prototype) notably by using Object.prototype.__proto__ or Object.setPrototypeOf(Object.prototype, otherObject) should fail with a TypeError as per spec.

This is the only exotic behavior of this object.

I chose to implement this by adding the virtual method IsProtoImmutable to RecyclableObject with the default return value false, and to override this function in ObjectPrototypeObject to return true. This allows for a future implementation of Object.setImmutablePrototype which would allow other objects to exhibit this behavior. A flag could be added which can be set, and this method would return the value of that flag. In that case, the implementation in ObjectPrototypeObject should remain hardcoded to false to avoid accidentally allowing the value if IsProtoImmutable to change.

See 19.1.3:
The Object prototype object is the intrinsic object %ObjectPrototype%.
The Object prototype object is an immutable prototype exotic object.
See 9.4.7:
An immutable prototype exotic object is an exotic object that has an immutable [[Prototype]] internal slot.

Fixes chakra-core#261
dilijev added a commit to dilijev/ChakraCore that referenced this issue Apr 27, 2016
This means that any attempts to set the [[Prototype]] slot of the Object Prototype Object (the object which is initially pointed to by Object.prototype) notably by using Object.prototype.__proto__ or Object.setPrototypeOf(Object.prototype, otherObject) should fail with a TypeError as per spec.

This is the only exotic behavior of this object.

I chose to implement this by adding the virtual method IsProtoImmutable to RecyclableObject with the default return value false, and to override this function in ObjectPrototypeObject to return true. This allows for a future implementation of Object.setImmutablePrototype which would allow other objects to exhibit this behavior. A flag could be added which can be set, and this method would return the value of that flag. In that case, the implementation in ObjectPrototypeObject should remain hardcoded to false to avoid accidentally allowing the value if IsProtoImmutable to change.

See 19.1.3:
The Object prototype object is the intrinsic object %ObjectPrototype%.
The Object prototype object is an immutable prototype exotic object.
See 9.4.7:
An immutable prototype exotic object is an exotic object that has an immutable [[Prototype]] internal slot.

Fixes chakra-core#261
dilijev added a commit to dilijev/ChakraCore that referenced this issue Apr 27, 2016
This means that any attempts to set the [[Prototype]] slot of the Object Prototype Object (the object which is initially pointed to by Object.prototype) notably by using Object.prototype.__proto__ or Object.setPrototypeOf(Object.prototype, otherObject) should fail with a TypeError as per spec.

This is the only exotic behavior of this object.

I chose to implement this by adding the virtual method IsProtoImmutable to RecyclableObject with the default return value false, and to override this function in ObjectPrototypeObject to return true. This allows for a future implementation of Object.setImmutablePrototype which would allow other objects to exhibit this behavior. A flag could be added which can be set, and this method would return the value of that flag. In that case, the implementation in ObjectPrototypeObject should remain hardcoded to false to avoid accidentally allowing the value if IsProtoImmutable to change.

Removed defunct test.

See 19.1.3:
The Object prototype object is the intrinsic object %ObjectPrototype%.
The Object prototype object is an immutable prototype exotic object.
See 9.4.7:
An immutable prototype exotic object is an exotic object that has an immutable [[Prototype]] internal slot.

Fixes chakra-core#261

Removed redundant and defunct tests, fixed error description.
chakrabot pushed a commit that referenced this issue Apr 28, 2016
… object.

Merge pull request #878 from dilijev:immproto
This means that any attempts to set the [[Prototype]] slot of the Object Prototype Object (the object which is initially pointed to by `Object.prototype`) notably by using `Object.prototype.__proto__` or `Object.setPrototypeOf(Object.prototype, otherObject)` should fail with a `TypeError` as per spec.

This is the only exotic behavior of this object.

I chose to implement this by adding the virtual method `IsProtoImmutable` to `RecyclableObject` with the default return value `false`, and to override this method in `ObjectPrototypeObject` to return `true`. This allows for a future implementation of `Object.setImmutablePrototype` which would allow other objects to exhibit this behavior. A flag could be added which can be set, and this method would return the value of that flag. In that case, the implementation in `ObjectPrototypeObject` should remain hardcoded to false to avoid accidentally allowing the value if `IsProtoImmutable` to change.

See [ES2016 19.1.3](https://tc39.github.io/ecma262/#sec-properties-of-the-object-prototype-object):
The Object prototype object is the intrinsic object %ObjectPrototype%.
The Object prototype object is an immutable prototype exotic object.
See [ES2016 9.4.7](https://tc39.github.io/ecma262/#sec-immutable-prototype-exotic-objects):
An immutable prototype exotic object is an exotic object that has an immutable [[Prototype]] internal slot.

Fixes #261

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/microsoft/chakracore/878)
<!-- Reviewable:end -->
@dilijev dilijev added the Fixed label Apr 28, 2016
chakrabot pushed a commit that referenced this issue Apr 29, 2016
…totype exotic object.

Merge pull request #878 from dilijev:immproto
This means that any attempts to set the [[Prototype]] slot of the Object Prototype Object (the object which is initially pointed to by `Object.prototype`) notably by using `Object.prototype.__proto__` or `Object.setPrototypeOf(Object.prototype, otherObject)` should fail with a `TypeError` as per spec.

This is the only exotic behavior of this object.

I chose to implement this by adding the virtual method `IsProtoImmutable` to `RecyclableObject` with the default return value `false`, and to override this method in `ObjectPrototypeObject` to return `true`. This allows for a future implementation of `Object.setImmutablePrototype` which would allow other objects to exhibit this behavior. A flag could be added which can be set, and this method would return the value of that flag. In that case, the implementation in `ObjectPrototypeObject` should remain hardcoded to false to avoid accidentally allowing the value if `IsProtoImmutable` to change.

See [ES2016 19.1.3](https://tc39.github.io/ecma262/#sec-properties-of-the-object-prototype-object):
The Object prototype object is the intrinsic object %ObjectPrototype%.
The Object prototype object is an immutable prototype exotic object.
See [ES2016 9.4.7](https://tc39.github.io/ecma262/#sec-immutable-prototype-exotic-objects):
An immutable prototype exotic object is an exotic object that has an immutable [[Prototype]] internal slot.

Fixes #261

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/microsoft/chakracore/878)
<!-- Reviewable:end -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants