bug 624364 - r=jorendorff
authorIgor Bukanov <igor@mir2.org>
Tue, 25 Jan 2011 00:04:29 +0100
changeset 61690 378cfa4ae4f53ad02167900355664110b9769213
parent 61689 824f69dad2bc82141bd6a7572cb5829306bcd424
child 61691 8835fffb27afe4de1580c98596abe3f10ea2d83c
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersjorendorff
bugs624364
milestone2.0b11pre
bug 624364 - r=jorendorff
js/src/jsscope.cpp
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -860,16 +860,40 @@ JSObject::addPropertyInternal(JSContext 
         return shape;
     }
 
     CHECK_SHAPE_CONSISTENCY(this);
     METER(addFails);
     return NULL;
 }
 
+/*
+ * Check and adjust the new attributes for the shape to make sure that our
+ * slot access optimizations are sound. It is responsibility of the callers to
+ * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]].
+ */
+inline bool
+CheckCanChangeAttrs(JSContext *cx, JSObject *obj, const Shape *shape, uintN *attrsp)
+{
+    if (shape->configurable())
+        return true;
+
+    /* A permanent property must stay permanent. */
+    *attrsp |= JSPROP_PERMANENT;
+
+    /* Reject attempts to remove a slot from the permanent data property. */
+    if (shape->isDataDescriptor() && shape->hasSlot() &&
+        (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))) {
+        obj->reportNotConfigurable(cx, shape->id);
+        return false;
+    }
+
+    return true;
+}
+
 const Shape *
 JSObject::putProperty(JSContext *cx, jsid id,
                       PropertyOp getter, PropertyOp setter,
                       uint32 slot, uintN attrs,
                       uintN flags, intN shortid)
 {
     JS_ASSERT(!JSID_IS_VOID(id));
 
@@ -905,16 +929,19 @@ JSObject::putProperty(JSContext *cx, jsi
             return NULL;
         }
         return new_shape;
     }
 
     /* Property exists: search must have returned a valid *spp. */
     JS_ASSERT(!SHAPE_IS_REMOVED(*spp));
 
+    if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
+        return NULL;
+    
     /*
      * 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->isAlias() && shape->hasSlot();
     uint32 oldSlot = shape->slot;
     if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
@@ -1061,16 +1088,20 @@ JSObject::changeProperty(JSContext *cx, 
 
     /* Don't allow method properties to be changed to have a getter. */
     JS_ASSERT_IF(getter != shape->rawGetter, !shape->isMethod());
 
     if (getter == PropertyStub)
         getter = NULL;
     if (setter == PropertyStub)
         setter = NULL;
+
+    if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
+        return NULL;
+    
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
         return shape;
 
     const Shape *newShape;
 
     /*
      * Dictionary-mode objects exclusively own their mutable shape structs, so
      * we simply modify in place.