Bug 828137, part 1 - Make Object.defineProperty fail on window elements. r=bz.
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 11 Feb 2015 11:38:36 -0600
changeset 233118 1d5e0ae90498a2675c5779fd32a27e03e2bb21ff
parent 233117 911612d952e61b18a04c22032c89ff9ef1923107
child 233119 68f9f9c4868b5eb78e7f7052046d8940137b01b3
push id28403
push usercbook@mozilla.com
push dateThu, 12 Mar 2015 08:14:30 +0000
treeherdermozilla-central@b6329532e4e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs828137
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 828137, part 1 - Make Object.defineProperty fail on window elements. r=bz.
dom/base/nsGlobalWindow.cpp
dom/base/test/test_window_indexing.html
js/public/Class.h
js/src/js.msg
js/src/jsapi.cpp
js/src/tests/js1_5/extensions/regress-385134.js
js/src/vm/Xdr.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -782,20 +782,19 @@ nsOuterWindowProxy::defineProperty(JSCon
                                    JS::Handle<JSObject*> proxy,
                                    JS::Handle<jsid> id,
                                    JS::MutableHandle<JSPropertyDescriptor> desc,
                                    JS::ObjectOpResult &result) const
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (IsArrayIndex(index)) {
     // Spec says to Reject whether this is a supported index or not,
-    // since we have no indexed setter or indexed creator.  That means
-    // throwing in strict mode (FIXME: Bug 828137), doing nothing in
-    // non-strict mode.
-    return result.succeed();
+    // since we have no indexed setter or indexed creator.  It is up
+    // to the caller to decide whether to throw a TypeError.
+    return result.failCantDefineWindowElement();
   }
 
   // For now, allow chrome code to define non-configurable properties
   // on windows, until we sort out what exactly the addon SDK is
   // doing.  In the meantime, this still allows us to test web compat
   // behavior.
   if (false && desc.isPermanent() && !nsContentUtils::IsCallerChrome()) {
     return ThrowErrorMessage(cx, MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW);
--- a/dom/base/test/test_window_indexing.html
+++ b/dom/base/test/test_window_indexing.html
@@ -45,19 +45,32 @@ https://bugzilla.mozilla.org/show_bug.cg
   // set() hook test
   window[1] = "FAIL";
   is(window[1].name, "y", "Second frame is still y");
   y.parentNode.removeChild(y);
   ok(!("1" in window), "We no longer have two subframes");
   is(window[1], undefined, "We should not have a value here");
 
   // defineProperty() hook test
+  function throws(errorCtor, f) {
+    try {
+      f();
+    } catch (exc) {
+      if (!(exc instanceof errorCtor))
+        throw exc;
+      return;
+    }
+    throw new Error("expected " + errCtor.name + ", no exception thrown: " + f);
+  }
+
   x.parentNode.appendChild(y);
-  Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
-				       writable: true })
+  throws(TypeError, function () {
+    Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
+                                         writable: true });
+  });
   y.parentNode.removeChild(y);
   ok(!("1" in window), "We no longer have two subframes, again");
   is(window[1], undefined, "We should not have a value here either");
 
   // More set() hook test
   window[1] = "FAIL3";
   ok(!("1" in window), "We shouldn't allow indexed expandos");
   is(window[1], undefined, "We should not have a value for an indexed expando");
@@ -71,18 +84,20 @@ https://bugzilla.mozilla.org/show_bug.cg
   ok(desc.enumerable, "Subframe should be configurable");
   ok(!desc.writable, "Subframe should not be writable");
   is(desc.value, y.contentWindow, "Subframe should have correct value");
 
   y.parentNode.removeChild(y);
   is(window[1], undefined, "And now we should be back to no [1] property");
 
   // And more defineProperty()
-  Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
-				       writable: true })
+  throws(TypeError, function () {
+    Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
+                                         writable: true });
+  });
   ok(!("1" in window), "Defining indexed properties really just shouldn't work");
   is(window[1], undefined, "Defining past end of list should not work");
 
   // Enumeration tests
   x.parentNode.appendChild(y);
 
   var names = Object.getOwnPropertyNames(window);
   is(names[0], "0", "Must start with 0");
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -128,18 +128,20 @@ class ObjectOpResult
         MOZ_ASSERT(msg != OkCode);
         code_ = msg;
         return true;
     }
 
     JS_PUBLIC_API(bool) failCantRedefineProp();
     JS_PUBLIC_API(bool) failReadOnly();
     JS_PUBLIC_API(bool) failGetterOnly();
+    JS_PUBLIC_API(bool) failCantDelete();
+
     JS_PUBLIC_API(bool) failCantSetInterposed();
-    JS_PUBLIC_API(bool) failCantDelete();
+    JS_PUBLIC_API(bool) failCantDefineWindowElement();
     JS_PUBLIC_API(bool) failCantDeleteWindowElement();
     JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty();
     JS_PUBLIC_API(bool) failCantPreventExtensions();
 
     uint32_t failureCode() const {
         MOZ_ASSERT(!ok());
         return uint32_t(code_);
     }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -474,11 +474,12 @@ MSG_DEF(JSMSG_SYMBOL_TO_NUMBER,        0
 
 // Atomics and futexes
 MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY,         0, JSEXN_TYPEERR, "invalid array type for the operation")
 MSG_DEF(JSMSG_ATOMICS_TOO_LONG,          0, JSEXN_RANGEERR, "timeout value too large")
 MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED,  0, JSEXN_ERR, "waiting is not allowed on this thread")
 
 // XPConnect wrappers and DOM bindings
 MSG_DEF(JSMSG_CANT_SET_INTERPOSED,      1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
+MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't define elements on a Window object")
 MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object")
 MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object")
 MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS,  0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -193,25 +193,31 @@ JS::ObjectOpResult::failReadOnly()
 
 JS_PUBLIC_API(bool)
 JS::ObjectOpResult::failGetterOnly()
 {
     return fail(JSMSG_GETTER_ONLY);
 }
 
 JS_PUBLIC_API(bool)
+JS::ObjectOpResult::failCantDelete()
+{
+    return fail(JSMSG_CANT_DELETE);
+}
+
+JS_PUBLIC_API(bool)
 JS::ObjectOpResult::failCantSetInterposed()
 {
     return fail(JSMSG_CANT_SET_INTERPOSED);
 }
 
 JS_PUBLIC_API(bool)
-JS::ObjectOpResult::failCantDelete()
-{
-    return fail(JSMSG_CANT_DELETE);
+JS::ObjectOpResult::failCantDefineWindowElement()
+{
+    return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT);
 }
 
 JS_PUBLIC_API(bool)
 JS::ObjectOpResult::failCantDeleteWindowElement()
 {
     return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT);
 }
 
--- a/js/src/tests/js1_5/extensions/regress-385134.js
+++ b/js/src/tests/js1_5/extensions/regress-385134.js
@@ -19,16 +19,20 @@ function test()
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
   if (typeof this.__defineSetter__ != 'undefined' && 
       typeof this.watch != 'undefined' &&
       typeof uneval != 'undefined')
   {
-    this.__defineSetter__(0, function(){});
+    try {
+      this.__defineSetter__(0, function(){});
+    } catch (exc) {
+      // In the browser, this fails. Ignore the error.
+    }
     this.watch(0, function(){});
     uneval(this);
   }
   reportCompare(expect, actual, summary);
 
   exitFunc ('test');
 }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 257;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 258;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 387,
+static_assert(JSErr_Limit == 388,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)