__proto__
On the one hand, proto is another potential security hole, and it prevents implementations from sharing prototype objects among multiple documents -- the link may be read-only but the object isn't. Function B called from function A with object O may hack O.proto and A can do nothing about it; suddenly all O-like objects in the system act differently.
On the other hand, Constructor.prototype is generally available for any Constructor, so it's hard to see what the real damage is -- it's not obviously worse than some other aspects of the language.
On the third hand, some implementations may have specialized objects for which no Constructor is available and for whom keeping [[Prototype]] unavailable is desirable. Similarly, some toolkits may have private prototype objects that are not available to client code because the constructor is hidden in a lexical scope (ES3) or package/namespace (ES4).
Introspection is great, but it assumes a lot about how trust works in the environment.
On 11/09/2007, Lars T Hansen <lth at acm.org> wrote:
On the one hand, proto is another potential security hole, and it prevents implementations from sharing prototype objects among multiple documents -- the link may be read-only but the object isn't. Function B called from function A with object O may hack O.proto and A can do nothing about it; suddenly all O-like objects in the system act differently.
On the other hand, Constructor.prototype is generally available for any Constructor, so it's hard to see what the real damage is -- it's not obviously worse than some other aspects of the language.
For ES3 code, exposing proto means that prototypes on constructors protected by scope (as is becoming practice by at least library writers today) are exposed, which they weren't before. It also means that a prototype that is thrown away after setting up the object will now be accessible.
On the third hand, some implementations may have specialized objects for which no Constructor is available and for whom keeping [[Prototype]] unavailable is desirable. Similarly, some toolkits may have private prototype objects that are not available to client code because the constructor is hidden in a lexical scope (ES3) or package/namespace (ES4).
Introspection is great, but it assumes a lot about how trust works in the environment.
Hmm. On another note: Would it be reasonable to standardise a way to attach a prototype chain to a plain object instanciator? (Instead of reading one out of an object...)
var
someObject={
mySharedValue: value},
someOtherObject={
"[[prototype]]": someObject};
This would get rid of the need for a function call (Crockford's object function for instance) for setting up plain ES3 prototypal inheritance, and would mean some structures that are not currently serialisable as JSON despite being plain value structures would become serialisable.
On 9/11/07, liorean <liorean at gmail.com> wrote:
On 11/09/2007, Lars T Hansen <lth at acm.org> wrote:
On the one hand, proto is another potential security hole, and it prevents implementations from sharing prototype objects among multiple documents -- the link may be read-only but the object isn't. Function B called from function A with object O may hack O.proto and A can do nothing about it; suddenly all O-like objects in the system act differently.
On the other hand, Constructor.prototype is generally available for any Constructor, so it's hard to see what the real damage is -- it's not obviously worse than some other aspects of the language.
For ES3 code, exposing proto means that prototypes on constructors protected by scope (as is becoming practice by at least library writers today) are exposed, which they weren't before.
OK, that's the problem I was alluding to in my "on the third hand".
It also means that a prototype that is thrown away after setting up the object will now be accessible.
That I don't get. The object is the prototype object of some other object, the garbage collector can't collect the proto until the referencing object can be collected. It's pretty clear to me that you can't fold the prototype into the object itself without a lot of extra machinery. Perhaps you can provide a concrete example?
On the third hand, some implementations may have specialized objects for which no Constructor is available and for whom keeping [[Prototype]] unavailable is desirable. Similarly, some toolkits may have private prototype objects that are not available to client code because the constructor is hidden in a lexical scope (ES3) or package/namespace (ES4).
Introspection is great, but it assumes a lot about how trust works in the environment.
Hmm. On another note: Would it be reasonable to standardise a way to attach a prototype chain to a plain object instanciator? (Instead of reading one out of an object...)
var someObject={ mySharedValue: value}, someOtherObject={ "[[prototype]]": someObject};
This would get rid of the need for a function call (Crockford's object function for instance) for setting up plain ES3 prototypal inheritance, and would mean some structures that are not currently serialisable as JSON despite being plain value structures would become serialisable.
I can't argue about the serialization bit.
I love to argue about performance, though, so I'll take your "get rid of the need for a function call" as an argument about performance and proceed from there :)
If function calls are so expensive that they dominate object creation time we should worry about how we can make them faster, I think, especially if the language gets in the way of good performance. It's true function calls are a little heavyweight in ES...
A quick test comparing 0-argument function calls to allocation of empty objects using {} syntax follows. Results are reported as the number of calls that can be made in the time it takes to perform one allocation.
On a MacBook Pro:
calls per alloc
Opera 9.5a1 3.48 Opera 9.2 0.66 Safari 2 0.68
On a Thinkpad T60p:
FF 2.0.0.6 2.88 IE 6 1.27 (at 1/10 the number of iterations because of the silly "slow script" dialog)
This probably includes a little GC time for the allocation test but that doesn't seem unfair. Test code included below.
This simplistic test indicates that some browsers (Opera 9.2, Safari 2) have particularly slow calls relative to allocations and so your concern may well be warranted. But if Safari 3 and to a lesser extent IE 7 perform better, the overhead of a call may not be much to worry about.
Obviously the test completely ignores the fact that, say, calls in Safari may be much faster than in another browser, it may just be that the allocator is superfast too, at which point the ratio is not very relevant. (That does not seem to be the case, though. The browsers are all pretty much comparable. The big change for Opera is explained by allocation running at half the speed in 9.5 while calls are much faster.)
--lars
function g() {}
function testalloc() { var x; for ( var i=0 ; i < 1000000 ; i++ ) { x = {}; } }
function testcall() { var x; for ( var i=0 ; i < 1000000 ; i++ ) { g(); } }
var t1 = new Date; testalloc(); var t2 = new Date; testcall(); var t3 = new Date; document.writeln("Calls per alloc = " + 1/((t3 - t2)/(t2 - t1)));
On 9/11/07, liorean <liorean at gmail.com> wrote:
It also means that a prototype that is thrown away after setting up the object will now be accessible.
On 11/09/2007, Lars T Hansen <lth at acm.org> wrote:
That I don't get. The object is the prototype object of some other object, the garbage collector can't collect the proto until the referencing object can be collected. It's pretty clear to me that you can't fold the prototype into the object itself without a lot of extra machinery. Perhaps you can provide a concrete example?
Not anything in production code. Conceptually:
function F(){}
/* add some prototype properties here */
newObj=new F;
F.prototype={constructor:F};
That way, you've protected the newObj.[[prototype]] object from being modified by throwing it away - the only reference to it is from newObj, and that one isn't exposed. The usefulness of doing this instead of using scope is not obvious to me, however, it was just another case of how to make a [[prototype]] unaccessible from the normal language mechanics that I could think of.
On 9/11/07, liorean <liorean at gmail.com> wrote:
This would get rid of the need for a function call (Crockford's object function for instance) for setting up plain ES3 prototypal inheritance, and would mean some structures that are not currently serialisable as JSON despite being plain value structures would become serialisable.
On 11/09/2007, Lars T Hansen <lth at acm.org> wrote:
I can't argue about the serialization bit.
I love to argue about performance, though, so I'll take your "get rid of the need for a function call" as an argument about performance and proceed from there :)
Actually, it's not performance that I was thinking of. I just prefer the option of making the prototype relation declarative in a JSON-like initialiser (obviously we need variable names for it to work, so it wouldn't be entirely compatible with current JSON) instead of requiring a call to a function where the only thing the function call would be there to do is to set up a reference to a prototype object. Not only do you need to do the call, by the way, you also need to change from object instanciator to member assignments.
It's mostly about giving the scenario a clean looking code. Contrast the following:
function inheritFrom(o){
function F(){}
F.prototype=o;
return new F;
}
var
a={ /* declare some properties*/ },
b=inheritFrom(a);
b['prop0']='blah';
b['prop1']='blah';
/* ... */
to the following:
var
a={ /* declare some properties*/ },
b={
"[[Prototype]]": a,
prop0: 'blah',
prop1: 'bleh'};
I would consider being able to keep using the object instanciator when you want to set up a relation like that a real plus when it comes to code clarity.
Is proto somehow a new security threat? proto has been around for ages in SM/FF and not only that, but it has been there in the more hazardous writable form. I just wanted it be actually included in the spec. Or is there some new functionality in ES4 that will somehow interact with proto to introduce a security threat? Kris ----- Original Message ---
proto breaks abstraction boundaries in the language -- it's just like function.caller, you get to look at and change objects that your caller may wish to keep secret from you. Whether it's actually a security threat depends on the details of the environment: whether your caller fits those criteria or not, or whether your run-time environment has objects whose constructors are not exposed to client code.
proto breaks abstraction boundaries in the language -- it's just
Hiding for the sake abstraction is more valuable than introspective visibility? I disagree, at least with JavaScript, IMHO JS's introspective nature is one of it's greatest strengths. Is there a precedence for this in other languages? Java is big on abstractions but inheritance is still introspectable (I realize that is not completely the same). And I believe that Self, the closest relative, makes the proto available throught .parent* property (I could be wrong about that).
security threat depends on the details of the environment: whether
Hasn't that security threat been evaluated by the years that this property has already been available?
Kris
On Sep 11, 2007, at 1:47 PM, Kris Zyp wrote:
proto breaks abstraction boundaries in the language -- it's just
Hiding for the sake abstraction is more valuable than introspective
visibility? I disagree, at least with JavaScript, IMHO JS's
introspective nature is one of it's greatest strengths. Is there a
precedence for this in other languages? Java is big on abstractions
but inheritance is still introspectable (I realize that is not
completely the same). And I believe that Self, the closest
relative, makes the proto available throught .parent* property (I
could be wrong about that).
Self has *-suffixed slots that constitute multiple prototypes per
object. Yeah, JS is reflection-happy, or was. Some of it was
distorted due to minimization (no activation reflection, so
fun.caller) and that wasn't standardized. And ES1 intentionally
censored activation object reflection, so much so that when closures
were standardized in ES3, the bug where |this| inside a nested
function does not match the outer function's |this| when the inner is
called from the outer inadvertently bit.
Reflection is two-edged. It breaks abstraction, removes some theorems
for free, and with mutation it can do a lot of damage (sometimes a
good thing ;-).
A read-only proto is hazardous for those factory closures that
hide the created object's prototype. Without proto, you can't get
at the prototype, which means you can enforce some integrity
properties about names not being found rather than being found in the
proto.
A read-write proto is unthinkable (and in SpiderMonkey, complete
with cycle detection :-P).
security threat depends on the details of the environment: whether
Hasn't that security threat been evaluated by the years that this
property has already been available?
It has, and while proto has been used in some Mozilla PoCs over
the years, it wasn't that big a deal. It was never exploited in the
wild that we know of. But it added attack surface and it exacted a
toll. I am not proposing it for ES4.
On Tue, 2007-09-11 at 13:47 -0700, Kris Zyp wrote:
__proto__ breaks abstraction boundaries in the language -- it's just
Hiding for the sake abstraction is more valuable than introspective visibility? I disagree, at least with JavaScript, IMHO JS's introspective nature is one of it's greatest strengths. Is there a precedence for this in other languages? Java is big on abstractions but inheritance is still introspectable (I realize that is not completely the same). And I believe that Self, the closest relative, makes the proto available throught .parent* property (I could be wrong about that).
I'd like a few cents on the subject of attacks: my research team is working on security in the context of Firefox extensions. While extensions are not the main focus of JavaScript, security decisions for JS2 will be critical for them.
One thing many applications/extensions need is a way to actually hide some information from other applications/extensions. While there's no way to fully hide something from someone who can mingle with the VM, at least, there should be some limits to JS2's introspections capabilities, unless we want extensions to become vectors for credit-card-number-stealing-attack .
I realise that a read-only proto probably can't be used for this type of attacks. But, well, I wanted this to be said before "introspection rulez" becomes written in stone.
On 9/11/07, Lars T Hansen <lth at acm.org> wrote:
On the one hand, proto is another potential security hole, and it prevents implementations from sharing prototype objects among multiple documents -- the link may be read-only but the object isn't. Function B called from function A with object O may hack O.proto and A can do nothing about it; suddenly all O-like objects in the system act differently.
On the other hand, Constructor.prototype is generally available for any Constructor, so it's hard to see what the real damage is -- it's not obviously worse than some other aspects of the language.
What I've found is that it's always giving wrong constructor property with inheritance chains.
A <-- B <-- C c = (new C).constructor;// A
So to do this, I can use a chaining technique to hardcode the inheritance structure reading proto or using hand-rolled constructor chaining, but then that requires that clients who try to get the constructor build their inheritance with the same approach that I do, and get an enumerable constructor property on their class as a side effect.
The chaining technique was published many years ago by Kevin Lindsey and used by some popular libraries like YUI.
How about a constructor property on the function instance?
On the third hand, some implementations may have specialized objects for which no Constructor is available and for whom keeping [[Prototype]] unavailable is desirable. Similarly, some toolkits may have private prototype objects that are not available to client code because the constructor is hidden in a lexical scope (ES3) or package/namespace (ES4).
Could they make these private for their class? Is [[Get]] modified to exclude private members in ES4?
How is prototype inheritance different than shadowing static members in Java? Are private static members a security problem in Java?
Here's an example showing how to use proto to get the constructor. developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Property_Inheritance_Revisited:Determining_Instance_Relationships
proto makes the language more transparent.
Introspection is great, but it assumes a lot about how trust works in the environment.
--lars
On 9/11/07, Kris Zyp <kriszyp at xucia.com> wrote:
The alternative above would standardize read-only proto, which would make that property no longer implementation-specific. But of course we have no proposal to do that. I realize this wasn't really the main subject... but could the proto property be defined in the spec (as readonly)? I would love to see that property standardized. Kris
Es4-discuss mailing list Es4-discuss at mozilla.org, mail.mozilla.org/listinfo/es4-discuss
Es4-discuss mailing list Es4-discuss at mozilla.org, mail.mozilla.org/listinfo/es4-discuss
-- Programming is a collaborative art.
On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
What I've found is that it's always giving wrong constructor property with inheritance chains.
A <-- B <-- C c = (new C).constructor;// A
So to do this, I can use a chaining technique to hardcode the inheritance structure reading proto or using hand-rolled constructor chaining, but then that requires that clients who try to get the constructor build their inheritance with the same approach that I do, and get an enumerable constructor property on their class as a side effect.
You get that if you do the following:
function A(){}
function B(){}
B.prototype=new A;
function C(){}
C.prototype=new B;
Because if you do that, you replace the prototype containing the original constructor property (e.g. a reference back to the function C) with an instance of another constructor (e.g. B), but that instance doesn't have the constructor property that the original prototype had. If you want to keep the constructor properties, you need to do that manually. (With the obvious result that then the constructor property will be enumerable. Which can be changed through adding a call on propertyIsEnumerable in ES4.)
The chaining technique was published many years ago by Kevin Lindsey and used by some popular libraries like YUI.
It's actually far older than that, and I think the Netscape JavaScript guides and references even contained a crash course in this. I think it's mentioned in my oldest JavaScript books, published around 1996.
How about a constructor property on the function instance?
Wouldn't help, the constructor property would have to be set on the object the constructor builds.
Which could be done, of course, it should be a simple thing to add that in the algorithm for [[Construct]]. But then we have the question of what to do with constructors that return other objects than that set up by steps 1 through 5 of the [[Construct]] algorithm. A constructor can return other objects, you know. You'd have to decide whether this property should be set up prior to step 6 in the algorithm or subsequent to step 7. If prior, only the original object that was created in step 1 gets it, if subsequent, return values get it even if they are not the same as the original object.
Actually, I think this would be a nice and simple fix to ES3 that probably wouldn't hurt much code out there.
On 2007-09-22, at 17:52 EDT, liorean wrote:
Which could be done, of course, it should be a simple thing to add that in the algorithm for [[Construct]]. But then we have the question of what to do with constructors that return other objects than that set up by steps 1 through 5 of the [[Construct]] algorithm. A constructor can return other objects, you know. You'd have to decide whether this property should be set up prior to step 6 in the algorithm or subsequent to step 7. If prior, only the original object that was created in step 1 gets it, if subsequent, return values get it even if they are not the same as the original object.
Dylan has a rule that the constructor must return an object that is a
subtype of the constructor. If that were enforced, I would see no
reason to reset the constructor property of the returned object.
Actually, I think this would be a nice and simple fix to ES3 that probably wouldn't hurt much code out there.
Agreed. As I mentioned elsewhere in this thread, we do this manually
in our framework for now.
All current engines I could try return Number.prototype
for:
12["__proto__"]
But the new spec says this should be a TypeError
.
It's more consistent with the other members of Object.prototype
to do an implicit ToObject here, and apparently matches existing implementations. Is it intentional that the spec is treating this as a TypeError
?
On Tue, Jul 16, 2013 at 6:33 PM, Luke Hoban <lukeh at microsoft.com> wrote:
All current engines I could try return
Number.prototype
for:
12["__proto__"]
But the new spec says this should be a
TypeError
.
What is the relevant part of the new spec?
What is the relevant part of the new spec?
In B.2.2.1, step #2 throws a TypeError
instead of doing a ToObject.
get Object.prototype.__proto__
The value of the [[Get]] attribute is a built-in function that requires no arguments. It performs the following steps:
1. Let O be the this value.
2. If Type(O) is not Object, then throw a TypeError exception.
3. Return the result of calling the [[GetInheritance]] internal method of O.
On Jul 16, 2013, at 6:33 PM, Luke Hoban wrote:
Is it intentional that the spec is treating this as a
TypeError
?
Well, it was intentional, but perhaps wrong. As you say, the set accessor probably needs to do a ToObject. The set accessor probably only needs to do a CheckObjectCoercible followed by an immediate return if the type of this is not Object
(the wrapper and hence it's modified [[Prototype]] isn't observable, so it doesn't actually need to be created).
File a bug, and I'll put the revised algorithms into the ticket.
Opened ecmascript#1586.
On Tue, Jul 16, 2013 at 7:01 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
Well, it was intentional, but perhaps wrong. As you say, the set accessor probably needs to do a ToObject.
Did you mean "...the get accessor..." ?
you might want to double check Object.getPrototypeOf(generic)
does the
same as Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get.call(generic)
.
Apologies if this is already the case.
off topic: any idea when Object.setPrototypeOf(generic, proto)
will be
rolled out and __proto__
not poisoned anymore ?
On Jul 17, 2013, at 9:12 AM, Andrea Giammarchi wrote:
you might want to double check
Object.getPrototypeOf(generic)
does the same asObject.getOwnPropertyDescriptor(Object.prototype, '__proto__').get.call(generic)
.
good point, done.
Andrea Giammarchi wrote:
off topic: any idea when
Object.setPrototypeOf(generic, proto)
will be rolled out and__proto__
not poisoned anymore ?
This is off-topic for es-discuss if you are asking about Chakra, JSC, SpiderMonkey, or V8. But since we are here, perhaps someone knows for each of those engines' plans (I do not).
I realize this wasn't really the main subject... but could the proto property be defined in the spec (as readonly)? I would love to see that property standardized. Kris