Bug 1082662 - Don't crash trying to mark a dictionary accessor shape whose getter/setter field has previously been mutated from a callable to |undefined|. r=terrence
authorJeff Walden <jwalden@mit.edu>
Tue, 14 Oct 2014 14:43:53 -0700
changeset 210467 cbde563962735c0acae142c53e1e625626d13ca1
parent 210466 d0e6c1ac03918a153e9b2c5d3df0b2280d57da09
child 210468 fb08ab7ef68ef659b6b80f45e86a1c6c14e1ff42
push id27654
push userryanvm@gmail.com
push dateWed, 15 Oct 2014 18:31:27 +0000
treeherdermozilla-central@a280a03c9f3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1082662
milestone36.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 1082662 - Don't crash trying to mark a dictionary accessor shape whose getter/setter field has previously been mutated from a callable to |undefined|. r=terrence
js/src/jspropertytree.cpp
js/src/tests/ecma_5/Object/clear-dictionary-accessor-getset.js
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -356,16 +356,19 @@ void
 ShapeGetterSetterRef::mark(JSTracer *trc)
 {
     // Update the current shape's entry in the parent KidsHash table if needed.
     // This is necessary as the computed hash includes the getter/setter
     // pointers.
 
     JSObject *obj = *objp;
     JSObject *prior = obj;
+    if (!prior)
+        return;
+
     trc->setTracingLocation(&*prior);
     gc::Mark(trc, &obj, "AccessorShape getter or setter");
     if (obj == *objp)
         return;
 
     Shape *parent = shape->parent;
     if (shape->inDictionary() || !parent->kids.isHash()) {
         *objp = obj;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Object/clear-dictionary-accessor-getset.js
@@ -0,0 +1,55 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = "clear-dictionary-accessor-getset.js";
+var BUGNUMBER = 1082662;
+var summary =
+  "Properly handle GC of a dictionary accessor property whose [[Get]] or " +
+  "[[Set]] has been changed to |undefined|";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function test(field)
+{
+  var prop = "[[" + field[0].toUpperCase() + field.substring(1) + "]]";
+  print("Testing for GC crashes after setting " + prop + " to undefined...");
+
+  function inner()
+  {
+     // Create an object with an accessor property.
+     var obj = { x: 42, get y() {}, set y(v) {} };
+
+     // 1) convert it to dictionary mode, in the process 2) creating a new
+     // version of that accessor property whose [[Get]] and [[Set]] are objects
+     // that trigger post barriers.
+     delete obj.x;
+
+     var desc = {};
+     desc[field] = undefined;
+
+     // Overwrite [[field]] with undefined.  Note #1 above is necessary so this
+     // is an actual *overwrite*, and not (possibly) a shape-tree fork that
+     // doesn't overwrite.
+     Object.defineProperty(obj, "y", desc);
+
+  }
+
+  inner();
+  gc(); // In unfixed code, this crashes trying to mark a null [[field]].
+}
+
+test("get");
+test("set");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");