Title: [206948] trunk
Revision
206948
Author
[email protected]
Date
2016-10-07 20:20:53 -0700 (Fri, 07 Oct 2016)

Log Message

Object.freeze() and seal() should throw if [[PreventExtensions]]() fails.
https://bugs.webkit.org/show_bug.cgi?id=163160

Reviewed by Saam Barati.

JSTests:

* stress/object-freeze-with-proxy-preventExtensions.js: Added.
* stress/object-seal-with-proxy-preventExtensions.js: Added.

Source/_javascript_Core:

See https://tc39.github.io/ecma262/#sec-object.freeze,
https://tc39.github.io/ecma262/#sec-object.seal, and
https://tc39.github.io/ecma262/#sec-setintegritylevel.  We need to call
preventExtensions first before proceeding to freeze / seal the object.  If
preventExtensions fails, we should throw a TypeError.

* runtime/ObjectConstructor.cpp:
(JSC::setIntegrityLevel):
(JSC::objectConstructorSeal):
(JSC::objectConstructorFreeze):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (206947 => 206948)


--- trunk/JSTests/ChangeLog	2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/JSTests/ChangeLog	2016-10-08 03:20:53 UTC (rev 206948)
@@ -1,3 +1,13 @@
+2016-10-07  Mark Lam  <[email protected]>
+
+        Object.freeze() and seal() should throw if [[PreventExtensions]]() fails.
+        https://bugs.webkit.org/show_bug.cgi?id=163160
+
+        Reviewed by Saam Barati.
+
+        * stress/object-freeze-with-proxy-preventExtensions.js: Added.
+        * stress/object-seal-with-proxy-preventExtensions.js: Added.
+
 2016-10-05  Yusuke Suzuki  <[email protected]>
 
         [DOMJIT] Add initial CheckDOM and CallDOM implementations

Added: trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js (0 => 206948)


--- trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js	                        (rev 0)
+++ trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js	2016-10-08 03:20:53 UTC (rev 206948)
@@ -0,0 +1,29 @@
+// See https://tc39.github.io/ecma262/#sec-object.freeze
+// See https://tc39.github.io/ecma262/#sec-setintegritylevel
+
+var x = [10];
+var visited = [];
+
+var proxy = new Proxy(x, {
+    preventExtensions() {
+        visited.push("proxy_preventExtensions");
+        return false;
+    }
+});
+
+var exception;
+try  {
+    visited.push("before_freeze");
+    Object.freeze(proxy);
+    visited.push("after_freeze");
+} catch (e) {
+    visited.push("catch");
+    exception = e;
+}
+
+var exceptionStr = "" + exception;
+if (!exceptionStr.startsWith("TypeError:"))
+    throw "Did not throw expected TypeError";
+
+if (visited != "before_freeze,proxy_preventExtensions,catch")
+    throw "ERROR: visited = " + visited;

Added: trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js (0 => 206948)


--- trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js	                        (rev 0)
+++ trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js	2016-10-08 03:20:53 UTC (rev 206948)
@@ -0,0 +1,29 @@
+// See https://tc39.github.io/ecma262/#sec-object.seal
+// See https://tc39.github.io/ecma262/#sec-setintegritylevel
+
+var x = [10];
+var visited = [];
+
+var proxy = new Proxy(x, {
+    preventExtensions() {
+        visited.push("proxy_preventExtensions");
+        return false;
+    }
+});
+
+var exception;
+try  {
+    visited.push("before_seal");
+    Object.seal(proxy);
+    visited.push("after_seal");
+} catch (e) {
+    visited.push("catch");
+    exception = e;
+}
+
+var exceptionStr = "" + exception;
+if (!exceptionStr.startsWith("TypeError:"))
+    throw "Did not throw expected TypeError";
+
+if (visited != "before_seal,proxy_preventExtensions,catch")
+    throw "ERROR: visited = " + visited;

Modified: trunk/Source/_javascript_Core/ChangeLog (206947 => 206948)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-08 03:20:53 UTC (rev 206948)
@@ -1,3 +1,21 @@
+2016-10-07  Mark Lam  <[email protected]>
+
+        Object.freeze() and seal() should throw if [[PreventExtensions]]() fails.
+        https://bugs.webkit.org/show_bug.cgi?id=163160
+
+        Reviewed by Saam Barati.
+
+        See https://tc39.github.io/ecma262/#sec-object.freeze,
+        https://tc39.github.io/ecma262/#sec-object.seal, and
+        https://tc39.github.io/ecma262/#sec-setintegritylevel.  We need to call
+        preventExtensions first before proceeding to freeze / seal the object.  If
+        preventExtensions fails, we should throw a TypeError.
+
+        * runtime/ObjectConstructor.cpp:
+        (JSC::setIntegrityLevel):
+        (JSC::objectConstructorSeal):
+        (JSC::objectConstructorFreeze):
+
 2016-10-06  Yusuke Suzuki  <[email protected]>
 
         [DOMJIT] Support slow path call

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (206947 => 206948)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2016-10-08 03:20:53 UTC (rev 206948)
@@ -471,6 +471,51 @@
     return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
 }
 
+enum class IntegrityLevel {
+    Sealed,
+    Frozen
+};
+
+template<IntegrityLevel level>
+bool setIntegrityLevel(ExecState* exec, VM& vm, JSObject* object)
+{
+    // See https://tc39.github.io/ecma262/#sec-setintegritylevel.
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    bool success = object->methodTable(vm)->preventExtensions(object, exec);
+    RETURN_IF_EXCEPTION(scope, false);
+    if (UNLIKELY(!success))
+        return false;
+
+    PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+    object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    RETURN_IF_EXCEPTION(scope, false);
+
+    PropertyNameArray::const_iterator end = properties.end();
+    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        Identifier propertyName = *iter;
+        if (vm.propertyNames->isPrivateName(propertyName))
+            continue;
+
+        PropertyDescriptor desc;
+        if (level == IntegrityLevel::Sealed)
+            desc.setConfigurable(false);
+        else {
+            if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
+                continue;
+
+            if (desc.isDataDescriptor())
+                desc.setWritable(false);
+
+            desc.setConfigurable(false);
+        }
+
+        object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
+        RETURN_IF_EXCEPTION(scope, false);
+    }
+    return true;
+}
+    
 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -487,31 +532,13 @@
         return JSValue::encode(obj);
     }
 
-    // 2. For each named own property name P of O,
-    PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
-    object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    bool success = setIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    PropertyNameArray::const_iterator end = properties.end();
-    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
-        Identifier propertyName = *iter;
-        if (exec->propertyNames().isPrivateName(propertyName))
-            continue;
-        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
-        PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
-            continue;
-        // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
-        desc.setConfigurable(false);
-        // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-        object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!success) {
+        throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.seal"));
+        return encodedJSValue();
     }
 
-    // 3. Set the [[Extensible]] internal property of O to false.
-    object->methodTable(vm)->preventExtensions(object, exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    // 4. Return O.
     return JSValue::encode(obj);
 }
 
@@ -525,35 +552,10 @@
         return object;
     }
 
-    // 2. For each named own property name P of O,
-    PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
-    object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    bool success = setIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object);
     RETURN_IF_EXCEPTION(scope, nullptr);
-    PropertyNameArray::const_iterator end = properties.end();
-    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
-        Identifier propertyName = *iter;
-        if (exec->propertyNames().isPrivateName(propertyName))
-            continue;
-        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
-        PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
-            continue;
-        // b. If IsDataDescriptor(desc) is true, then
-        // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
-        if (desc.isDataDescriptor())
-            desc.setWritable(false);
-        // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
-        desc.setConfigurable(false);
-        // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-        object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
-        RETURN_IF_EXCEPTION(scope, nullptr);
-    }
-
-    // 3. Set the [[Extensible]] internal property of O to false.
-    object->methodTable(vm)->preventExtensions(object, exec);
-    RETURN_IF_EXCEPTION(scope, nullptr);
-
-    // 4. Return O.
+    if (!success)
+        return throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.freeze"));
     return object;
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to