Bug 1407058 - Fix isDataProperty to return false for accessors with nullptr getter/setter. r=evilpie
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 12 Oct 2017 11:06:55 +0200
changeset 385669 0308ff8eba0361c2e00b148e7d6b7ea30d1f6e91
parent 385668 4d27389bae4c440e058b01d30ebb75c3d577f7cd
child 385670 6210553ddc6c968bbbdcd3b4ddb7368f3e41fca9
push id96095
push userjandemooij@gmail.com
push dateThu, 12 Oct 2017 09:09:34 +0000
treeherdermozilla-inbound@0308ff8eba03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie
bugs1407058
milestone58.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 1407058 - Fix isDataProperty to return false for accessors with nullptr getter/setter. r=evilpie
js/src/jit-test/tests/basic/bug1407058.js
js/src/vm/Shape.cpp
js/src/vm/Shape.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1407058.js
@@ -0,0 +1,16 @@
+"use strict";
+function f() {
+    var o = {};
+    Object.defineProperty(o, "x", {get: undefined, set: undefined});
+    for (var i = 0; i < 20; i++) {
+        var ex = null;
+        try {
+            o.x = 9;
+        } catch (e) {
+            ex = e;
+        }
+        assertEq(ex instanceof TypeError, true);
+        assertEq(o.x, undefined);
+    }
+}
+f();
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -741,17 +741,17 @@ NativeObject::putProperty(JSContext* cx,
 
     /*
      * If the caller wants to allocate a slot, but doesn't care which slot,
      * copy the existing shape's slot into slot so we can match shape, if all
      * other members match.
      */
     bool hadSlot = shape->isDataProperty();
     uint32_t oldSlot = shape->maybeSlot();
-    bool needSlot = !getter && !setter;
+    bool needSlot = Shape::isDataProperty(attrs, getter, setter);
     if (needSlot && slot == SHAPE_INVALID_SLOT && hadSlot)
         slot = oldSlot;
 
     Rooted<UnownedBaseShape*> nbase(cx);
     {
         RootedShape shape(cx, obj->lastProperty());
         nbase = GetBaseShapeForNewShape(cx, shape, id);
         if (!nbase)
@@ -784,17 +784,17 @@ NativeObject::putProperty(JSContext* cx,
     if (obj->inDictionaryMode()) {
         /*
          * Updating some property in a dictionary-mode object. Create a new
          * shape for the existing property, and also generate a new shape for
          * the last property of the dictionary (unless the modified property
          * is also the last property).
          */
         bool updateLast = (shape == obj->lastProperty());
-        bool accessorShape = getter || setter || (attrs & (JSPROP_GETTER | JSPROP_SETTER));
+        bool accessorShape = !Shape::isDataProperty(attrs, getter, setter);
         shape = NativeObject::replaceWithNewEquivalentShape(cx, obj, shape, nullptr,
                                                             accessorShape);
         if (!shape)
             return nullptr;
         if (!updateLast && !NativeObject::generateOwnShape(cx, obj))
             return nullptr;
 
         /*
@@ -867,17 +867,17 @@ NativeObject::putProperty(JSContext* cx,
 /* static */ Shape*
 NativeObject::changeProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
                              unsigned attrs, GetterOp getter, SetterOp setter)
 {
     MOZ_ASSERT(obj->containsPure(shape));
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
 #ifdef DEBUG
-    bool needSlot = !getter && !setter;
+    bool needSlot = Shape::isDataProperty(attrs, getter, setter);
     MOZ_ASSERT_IF(shape->isDataProperty() != needSlot, needSlot);
 #endif
 
     MarkTypePropertyNonData(cx, obj, shape->propid());
 
     AssertCanChangeAttrs(shape, attrs);
 
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1008,19 +1008,23 @@ class Shape : public gc::TenuredCell
                maybeSlot() == aslot &&
                attrs == aattrs &&
                getter() == rawGetter &&
                setter() == rawSetter;
     }
 
     BaseShape* base() const { return base_.get(); }
 
+    static bool isDataProperty(unsigned attrs, GetterOp getter, SetterOp setter) {
+        return !(attrs & (JSPROP_GETTER | JSPROP_SETTER)) && !getter && !setter;
+    }
+
     bool isDataProperty() const {
         MOZ_ASSERT(!isEmptyShape());
-        return !getter() && !setter();
+        return isDataProperty(attrs, getter(), setter());
     }
     uint32_t slot() const { MOZ_ASSERT(isDataProperty() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
         return slotInfo & SLOT_MASK;
     }
 
     bool isEmptyShape() const {
         MOZ_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
@@ -1471,17 +1475,17 @@ struct StackShape
             flags &= ~Shape::ACCESSOR_SHAPE;
 
         this->rawGetter = rawGetter;
         this->rawSetter = rawSetter;
     }
 
     bool isDataProperty() const {
         MOZ_ASSERT(!JSID_IS_EMPTY(propid));
-        return !rawGetter && !rawSetter;
+        return Shape::isDataProperty(attrs, rawGetter, rawSetter);
     }
     bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
 
     uint32_t slot() const { MOZ_ASSERT(isDataProperty() && !hasMissingSlot()); return slot_; }
     uint32_t maybeSlot() const { return slot_; }
 
     void setSlot(uint32_t slot) {
         MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);