Title: [109949] trunk
Revision
109949
Author
[email protected]
Date
2012-03-06 12:20:04 -0800 (Tue, 06 Mar 2012)

Log Message

writable/configurable not respected for some properties of Function/String/Arguments
https://bugs.webkit.org/show_bug.cgi?id=80436

Reviewed by Oliver Hunt.

Special properties should behave like regular properties.

Source/_javascript_Core: 

* runtime/Arguments.cpp:
(JSC::Arguments::defineOwnProperty):
    - Mis-nested logic for making read-only properties non-live.
* runtime/JSFunction.cpp:
(JSC::JSFunction::put):
    - arguments/length/caller are non-writable, non-configurable - reject appropriately.
(JSC::JSFunction::deleteProperty):
    - Attempting to delete prototype/caller should fail.
(JSC::JSFunction::defineOwnProperty):
    - Ensure prototype is reified on attempt to reify it.
    - arguments/length/caller are non-writable, non-configurable - reject appropriately.
* runtime/JSFunction.h:
    - added declaration for defineOwnProperty.
(JSFunction):
* runtime/StringObject.cpp:
(JSC::StringObject::put):
    - length is non-writable, non-configurable - reject appropriately.

LayoutTests: 

* fast/js/mozilla/strict/10.6-expected.txt:
* fast/js/mozilla/strict/15.3.5.1-expected.txt:
* fast/js/mozilla/strict/15.3.5.2-expected.txt:
* fast/js/mozilla/strict/15.5.5.1-expected.txt:
    - Check in passing test results.
* fast/js/script-tests/arguments.js:
    - Fix test - this was asserting incorrect behaviour.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (109948 => 109949)


--- trunk/LayoutTests/ChangeLog	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/ChangeLog	2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,3 +1,20 @@
+2012-03-06  Gavin Barraclough  <[email protected]>
+
+        writable/configurable not respected for some properties of Function/String/Arguments
+        https://bugs.webkit.org/show_bug.cgi?id=80436
+
+        Reviewed by Oliver Hunt.
+
+        Special properties should behave like regular properties.
+
+        * fast/js/mozilla/strict/10.6-expected.txt:
+        * fast/js/mozilla/strict/15.3.5.1-expected.txt:
+        * fast/js/mozilla/strict/15.3.5.2-expected.txt:
+        * fast/js/mozilla/strict/15.5.5.1-expected.txt:
+            - Check in passing test results.
+        * fast/js/script-tests/arguments.js:
+            - Fix test - this was asserting incorrect behaviour.
+
 2012-03-06  Stephen White  <[email protected]>
 
         Unreviewed, rolling out r109840.

Modified: trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt (109948 => 109949)


--- trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt	2012-03-06 20:20:04 UTC (rev 109949)
@@ -28,13 +28,13 @@
 return (delete arguments[0]);
 })(0, 1, 2, 3); is true
 PASS true === true
-FAIL 'use strict'; (function f() {
+PASS 'use strict'; (function f() {
 Object.defineProperties(arguments, {1: { writable: false },
                                     2: { configurable: false },
                                     3: { writable: false,
                                         configurable: false }});
 return (arguments[1] = 42);
-})(0, 1, 2, 3); should throw an instance of TypeError
+})(0, 1, 2, 3); threw exception of type TypeError.
 PASS (function f() {
 Object.defineProperties(arguments, {1: { writable: false },
                                     2: { configurable: false },
@@ -88,13 +88,13 @@
 return (delete arguments[2]);
 })(0, 1, 2, 3); is false
 PASS true === true
-FAIL 'use strict'; (function f() {
+PASS 'use strict'; (function f() {
 Object.defineProperties(arguments, {1: { writable: false },
                                     2: { configurable: false },
                                     3: { writable: false,
                                         configurable: false }});
 return (arguments[3] = 42);
-})(0, 1, 2, 3); should throw an instance of TypeError
+})(0, 1, 2, 3); threw exception of type TypeError.
 PASS (function f() {
 Object.defineProperties(arguments, {1: { writable: false },
                                     2: { configurable: false },

Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt (109948 => 109949)


--- trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt	2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,4 +1,4 @@
-FAIL 'use strict'; var f = fn(); f.length = 1; f.length should throw an instance of TypeError
+PASS 'use strict'; var f = fn(); f.length = 1; f.length threw exception of type TypeError.
 PASS var f = fn(); f.length = 1; f.length is 3
 PASS true === true
 PASS 'use strict'; var f = fn(); delete f.length threw exception of type TypeError.

Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt (109948 => 109949)


--- trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt	2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,5 +1,5 @@
-FAIL 'use strict'; var f = fn(); delete f.prototype should throw an instance of TypeError
-FAIL var f = fn(); delete f.prototype should be false. Was true.
+PASS 'use strict'; var f = fn(); delete f.prototype threw exception of type TypeError.
+PASS var f = fn(); delete f.prototype is false
 PASS true === true
  PASSED! 
 PASS successfullyParsed is true

Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt (109948 => 109949)


--- trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt	2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,4 +1,4 @@
-FAIL 'use strict'; var s = str(); s.length = 1; s.length should throw an instance of TypeError
+PASS 'use strict'; var s = str(); s.length = 1; s.length threw exception of type TypeError.
 PASS var s = str(); s.length = 1; s.length is 3
 PASS true === true
 PASS 'use strict'; var s = str(); delete s.length threw exception of type TypeError.

Modified: trunk/LayoutTests/fast/js/script-tests/arguments.js (109948 => 109949)


--- trunk/LayoutTests/fast/js/script-tests/arguments.js	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/script-tests/arguments.js	2012-03-06 20:20:04 UTC (rev 109949)
@@ -623,7 +623,8 @@
     shouldBeTrue(String( a1 === 301 ));
     shouldBeTrue(String( arguments[1] === 201 ));
 
-    // When a2 is make read-only the value is set, but it is no longer live.
+    // When a2 is made read-only the value is set, but it is no longer live.
+    // (per 10.6 [[DefineOwnProperty]] 5.b.ii.1)
     shouldBeTrue(String( a2 === 202 ));
     shouldBeTrue(String( arguments[2] === 202 ));
     a2 = 302;
@@ -633,14 +634,15 @@
     shouldBeTrue(String( a2 === 302 ));
     shouldBeTrue(String( arguments[2] === 202 ));
 
-    // When a3 is make read-only it remains live.
+    // When a3 is made read-only, it is no longer live.
+    // (per 10.6 [[DefineOwnProperty]] 5.b.ii.1)
     shouldBeTrue(String( a3 === 103 ));
     shouldBeTrue(String( arguments[3] === 103 ));
     a3 = 303;
     shouldBeTrue(String( a3 === 303 ));
-    shouldBeTrue(String( arguments[3] === 303 ));
+    shouldBeTrue(String( arguments[3] === 103 ));
     arguments[3] = 403;
-    shouldBeTrue(String( a3 === 403 ));
-    shouldBeTrue(String( arguments[3] === 403 ));
+    shouldBeTrue(String( a3 === 303 ));
+    shouldBeTrue(String( arguments[3] === 103 ));
 
 })(100,101,102,103);

Modified: trunk/Source/_javascript_Core/ChangeLog (109948 => 109949)


--- trunk/Source/_javascript_Core/ChangeLog	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,3 +1,30 @@
+2012-03-06  Gavin Barraclough  <[email protected]>
+
+        writable/configurable not respected for some properties of Function/String/Arguments
+        https://bugs.webkit.org/show_bug.cgi?id=80436
+
+        Reviewed by Oliver Hunt.
+
+        Special properties should behave like regular properties.
+
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::defineOwnProperty):
+            - Mis-nested logic for making read-only properties non-live.
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::put):
+            - arguments/length/caller are non-writable, non-configurable - reject appropriately.
+        (JSC::JSFunction::deleteProperty):
+            - Attempting to delete prototype/caller should fail.
+        (JSC::JSFunction::defineOwnProperty):
+            - Ensure prototype is reified on attempt to reify it.
+            - arguments/length/caller are non-writable, non-configurable - reject appropriately.
+        * runtime/JSFunction.h:
+            - added declaration for defineOwnProperty.
+        (JSFunction):
+        * runtime/StringObject.cpp:
+        (JSC::StringObject::put):
+            - length is non-writable, non-configurable - reject appropriately.
+
 2012-03-06  Ulan Degenbaev  <[email protected]>
 
         TypedArray subarray call for subarray does not clamp the end index parameter properly

Modified: trunk/Source/_javascript_Core/runtime/Arguments.cpp (109948 => 109949)


--- trunk/Source/_javascript_Core/runtime/Arguments.cpp	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/Arguments.cpp	2012-03-06 20:20:04 UTC (rev 109949)
@@ -320,12 +320,15 @@
             if (descriptor.isAccessorDescriptor()) {
                 // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
                 thisObject->d->deletedArguments[i] = true;
-            } else if (descriptor.value()) { // b. Else i. If Desc.[[Value]] is present, then
+            } else { // b. Else
+                // i. If Desc.[[Value]] is present, then
                 // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
+                if (descriptor.value())
+                    thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value());
                 // ii. If Desc.[[Writable]] is present and its value is false, then
-                thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value());
+                // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
                 if (descriptor.writablePresent() && !descriptor.writable())
-                    thisObject->d->deletedArguments[i] = true; // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
+                    thisObject->d->deletedArguments[i] = true;
             }
         }
 

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (109948 => 109949)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2012-03-06 20:20:04 UTC (rev 109949)
@@ -337,8 +337,11 @@
         Base::put(thisObject, exec, propertyName, value, slot);
         return;
     }
-    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) {
+        if (slot.isStrictMode())
+            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
         return;
+    }
     Base::put(thisObject, exec, propertyName, value, slot);
 }
 
@@ -347,11 +350,64 @@
     JSFunction* thisObject = jsCast<JSFunction*>(cell);
     if (thisObject->isHostFunction())
         return Base::deleteProperty(thisObject, exec, propertyName);
-    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().prototype || propertyName == exec->propertyNames().caller)
         return false;
     return Base::deleteProperty(thisObject, exec, propertyName);
 }
 
+bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
+{
+    JSFunction* thisObject = jsCast<JSFunction*>(object);
+    if (thisObject->isHostFunction())
+        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+
+    if (propertyName == exec->propertyNames().prototype) {
+        // Make sure prototype has been reified, such that it can only be overwritten
+        // following the rules set out in ECMA-262 8.12.9.
+        PropertySlot slot;
+        thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+    } else if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) {
+        if (!object->isExtensible()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+            return false;
+        }
+        if (descriptor.configurablePresent() && descriptor.configurable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+            return false;
+        }
+        if (descriptor.enumerablePresent() && descriptor.enumerable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+            return false;
+        }
+        if (descriptor.isAccessorDescriptor()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+            return false;
+        }
+        if (descriptor.writablePresent() && descriptor.writable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+            return false;
+        }
+        if (!descriptor.value())
+            return true;
+        if (propertyName == exec->propertyNames().arguments && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject)))
+            return true;
+        if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount())))
+            return true;
+        if (propertyName == exec->propertyNames().caller && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject)))
+            return true;
+        if (throwException)
+            throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
+        return false;
+    }
+
+    return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+}
+
 // ECMA 13.2.2 [[Construct]]
 ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
 {

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (109948 => 109949)


--- trunk/Source/_javascript_Core/runtime/JSFunction.h	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h	2012-03-06 20:20:04 UTC (rev 109949)
@@ -133,6 +133,7 @@
         static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
         static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
         static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties);
+        static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
 
         static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
 

Modified: trunk/Source/_javascript_Core/runtime/StringObject.cpp (109948 => 109949)


--- trunk/Source/_javascript_Core/runtime/StringObject.cpp	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/StringObject.cpp	2012-03-06 20:20:04 UTC (rev 109949)
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "StringObject.h"
 
+#include "Error.h"
 #include "PropertyNameArray.h"
 
 namespace JSC {
@@ -68,11 +69,56 @@
 
 void StringObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
-    if (propertyName == exec->propertyNames().length)
+    if (propertyName == exec->propertyNames().length) {
+        if (slot.isStrictMode())
+            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
         return;
+    }
     JSObject::put(cell, exec, propertyName, value, slot);
 }
 
+bool StringObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
+{
+    StringObject* thisObject = jsCast<StringObject*>(object);
+
+    if (propertyName == exec->propertyNames().length) {
+        if (!object->isExtensible()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+            return false;
+        }
+        if (descriptor.configurablePresent() && descriptor.configurable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+            return false;
+        }
+        if (descriptor.enumerablePresent() && descriptor.enumerable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+            return false;
+        }
+        if (descriptor.isAccessorDescriptor()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+            return false;
+        }
+        if (descriptor.writablePresent() && descriptor.writable()) {
+            if (throwException)
+                throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+            return false;
+        }
+        if (!descriptor.value())
+            return true;
+        if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->internalValue()->length())))
+            return true;
+        if (throwException)
+            throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
+        return false;
+    }
+
+    return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+}
+
 bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
 {
     StringObject* thisObject = jsCast<StringObject*>(cell);

Modified: trunk/Source/_javascript_Core/runtime/StringObject.h (109948 => 109949)


--- trunk/Source/_javascript_Core/runtime/StringObject.h	2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/StringObject.h	2012-03-06 20:20:04 UTC (rev 109949)
@@ -53,6 +53,7 @@
 
         static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
         static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+        static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
 
         static const JS_EXPORTDATA ClassInfo s_info;
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to