Bug 660517 - Kill XML objects as prototypes. r=mrbkap, a=asa
authorJeff Walden <jwalden@mit.edu>
Mon, 18 Jul 2011 15:22:16 -0700
changeset 70532 fda101def1ec85e6b2a102a77fa9a565cf06c6fe
parent 70531 65ed6316d72dcabecd886318e53fdbf357c26e82
child 70533 1c05f5b86b7b064b6381b484ff5e37cc9fd8ffad
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersmrbkap, asa
bugs660517
milestone6.0
Bug 660517 - Kill XML objects as prototypes. r=mrbkap, a=asa
js/src/js.msg
js/src/jsobj.cpp
js/src/tests/e4x/extensions/jstests.list
js/src/tests/e4x/extensions/regress-305335.js
js/src/tests/e4x/extensions/xml-as-proto.js
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -345,8 +345,9 @@ MSG_DEF(JSMSG_SC_RECURSION,           26
 MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT,   263, 0, JSEXN_TYPEERR, "can't wrap XML objects")
 MSG_DEF(JSMSG_BAD_CLONE_VERSION,      264, 0, JSEXN_ERR, "unsupported structured clone version")
 MSG_DEF(JSMSG_CANT_CLONE_OBJECT,      265, 0, JSEXN_TYPEERR, "can't clone object")
 MSG_DEF(JSMSG_NON_NATIVE_SCOPE,       266, 0, JSEXN_TYPEERR, "non-native scope object")
 MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 267, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
 MSG_DEF(JSMSG_INVALID_FOR_IN_INIT,    268, 0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer")
 MSG_DEF(JSMSG_CLEARED_SCOPE,          269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope")
 MSG_DEF(JSMSG_INVALID_DATE,           270, 0, JSEXN_RANGEERR, "invalid date")
+MSG_DEF(JSMSG_XML_PROTO_FORBIDDEN,    271, 0, JSEXN_TYPEERR, "can't set prototype of an object to an XML value")
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2583,16 +2583,23 @@ obj_create(JSContext *cx, uintN argc, Va
         if (!bytes)
             return JS_FALSE;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object or null");
         JS_free(cx, bytes);
         return JS_FALSE;
     }
 
+    if (JSObject *proto = v.toObjectOrNull()) {
+        if (proto->isXML()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
+            return false;
+        }
+    }
+
     /*
      * Use the callee's global as the parent of the new object to avoid dynamic
      * scoping (i.e., using the caller's global).
      */
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, v.toObjectOrNull(),
                                                         vp->toObject().getGlobal());
     if (!obj)
         return JS_FALSE;
@@ -4158,16 +4165,21 @@ SetProto(JSContext *cx, JSObject *obj, J
     JS_ASSERT_IF(!checkForCycles, obj != proto);
     JS_ASSERT(obj->isExtensible());
 
     if (obj->isNative()) {
         if (!obj->ensureClassReservedSlots(cx))
             return false;
     }
 
+    if (proto && proto->isXML()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
+        return false;
+    }
+
     /*
      * Regenerate property cache shape ids for all of the scopes along the
      * old prototype chain to invalidate their property cache entries, in
      * case any entries were filled by looking up through obj.
      */
     JSObject *oldproto = obj;
     while (oldproto && oldproto->isNative()) {
         oldproto->protoShapeChange(cx);
--- a/js/src/tests/e4x/extensions/jstests.list
+++ b/js/src/tests/e4x/extensions/jstests.list
@@ -19,8 +19,9 @@ script regress-374163.js
 script regress-410192.js
 script regress-450871-01.js
 script regress-450871-02.js
 script regress-462734-01.js
 script extensibility.js
 script regress-595207.js
 script json-stringify-dropping-xml-elements.js
 script stringify-xml.js
+script xml-as-proto.js
--- a/js/src/tests/e4x/extensions/regress-305335.js
+++ b/js/src/tests/e4x/extensions/regress-305335.js
@@ -41,17 +41,24 @@ var summary = "Regression - XML instance
 var BUGNUMBER = 305335;
 var actual = 'No Crash';
 var expect = 'No Crash';
 
 printBugNumber(BUGNUMBER);
 START(summary);
 
 var o = new Number(0);
-o.__proto__ = XML();
+try
+{
+    o.__proto__ = XML();
+}
+catch (e)
+{
+    assertEq(e instanceof TypeError, true);
+}
 
 try
 { 
     o.parent();
 }
 catch(e)
 {
     printStatus('Exception: ' + e);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/e4x/extensions/xml-as-proto.js
@@ -0,0 +1,50 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+try
+{
+  var r = Object.create(<a/>);
+  throw new Error("didn't throw, got " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError for Object.create, got: " + e);
+}
+
+try
+{
+  var obj = {};
+  obj.__proto__ = <b/>;
+  throw new Error("didn't throw setting obj.__proto__");
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError for obj.__proto__, got: " + e);
+}
+
+try
+{
+  var obj = {};
+  obj.function::__proto__ = <b/>;
+  throw new Error("didn't throw setting xml.function::__proto__");
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError for function::__proto__, got: " + e);
+}
+
+var obj = <a/>;
+var kid = obj.__proto__ = <b>c</b>;
+assertEq(Object.getPrototypeOf(obj) != kid, true);
+assertEq(obj.children().length(), 1);
+assertEq(obj[0] == kid, true);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");