Changeset 207178 in webkit


Ignore:
Timestamp:
Oct 11, 2016 4:25:38 PM (8 years ago)
Author:
mark.lam@apple.com
Message:

Array.prototype.concat should not modify frozen objects.
https://bugs.webkit.org/show_bug.cgi?id=163302

Reviewed by Filip Pizlo.

JSTests:

  • stress/array-concat-on-frozen-object.js: Added.

Source/JavaScriptCore:

The ES6 spec for Array.prototype.concat states that it uses the
CreateDataPropertyOrThrow() to add items to the result array. The spec for
CreateDataPropertyOrThrow states:

"This abstract operation creates a property whose attributes are set to the same
defaults used for properties created by the ECMAScript language assignment
operator. Normally, the property will not already exist. If it does exist and is
not configurable or if O is not extensible, DefineOwnProperty? will return
false causing this operation to throw a TypeError exception."

Since the properties of frozen objects are not extensible, not configurable, and
not writable, Array.prototype.concat should fail to write to the result array if
it is frozen.

Ref: https://tc39.github.io/ecma262/#sec-array.prototype.concat,
https://tc39.github.io/ecma262/#sec-createdatapropertyorthrow, and
https://tc39.github.io/ecma262/#sec-createdataproperty.

The fix consists of 2 parts:

  1. moveElement() should use the PutDirectIndexShouldThrow mode when invoking putDirectIndex(), and
  2. SparseArrayValueMap::putDirect() should check for the case where the property is read only.

(2) ensures that we don't write into a non-writable property.
(1) ensures that we throw a TypeError for attempts to write to a non-writeable
property.

  • runtime/ArrayPrototype.cpp:

(JSC::moveElements):

  • runtime/SparseArrayValueMap.cpp:

(JSC::SparseArrayValueMap::putDirect):

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207060 r207178  
     12016-10-11  Mark Lam  <mark.lam@apple.com>
     2
     3        Array.prototype.concat should not modify frozen objects.
     4        https://bugs.webkit.org/show_bug.cgi?id=163302
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * stress/array-concat-on-frozen-object.js: Added.
     9
    1102016-10-11  Saam Barati  <sbarati@apple.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r207166 r207178  
     12016-10-11  Mark Lam  <mark.lam@apple.com>
     2
     3        Array.prototype.concat should not modify frozen objects.
     4        https://bugs.webkit.org/show_bug.cgi?id=163302
     5
     6        Reviewed by Filip Pizlo.
     7
     8        The ES6 spec for Array.prototype.concat states that it uses the
     9        CreateDataPropertyOrThrow() to add items to the result array.  The spec for
     10        CreateDataPropertyOrThrow states:
     11
     12        "This abstract operation creates a property whose attributes are set to the same
     13        defaults used for properties created by the ECMAScript language assignment
     14        operator. Normally, the property will not already exist. If it does exist and is
     15        not configurable or if O is not extensible, [[DefineOwnProperty]] will return
     16        false causing this operation to throw a TypeError exception."
     17
     18        Since the properties of frozen objects are not extensible, not configurable, and
     19        not writable, Array.prototype.concat should fail to write to the result array if
     20        it is frozen.
     21
     22        Ref: https://tc39.github.io/ecma262/#sec-array.prototype.concat,
     23        https://tc39.github.io/ecma262/#sec-createdatapropertyorthrow, and
     24        https://tc39.github.io/ecma262/#sec-createdataproperty.
     25
     26        The fix consists of 2 parts:
     27        1. moveElement() should use the PutDirectIndexShouldThrow mode when invoking
     28           putDirectIndex(), and
     29        2. SparseArrayValueMap::putDirect() should check for the case where the property
     30           is read only.
     31
     32        (2) ensures that we don't write into a non-writable property.
     33        (1) ensures that we throw a TypeError for attempts to write to a non-writeable
     34        property.
     35
     36        * runtime/ArrayPrototype.cpp:
     37        (JSC::moveElements):
     38        * runtime/SparseArrayValueMap.cpp:
     39        (JSC::SparseArrayValueMap::putDirect):
     40
    1412016-10-11  Yusuke Suzuki  <utatane.tea@gmail.com>
    242
  • trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp

    r207036 r207178  
    10791079            JSValue value = source->tryGetIndexQuickly(i);
    10801080            if (value) {
    1081                 target->putDirectIndex(exec, targetOffset + i, value);
     1081                target->putDirectIndex(exec, targetOffset + i, value, 0, PutDirectIndexShouldThrow);
    10821082                RETURN_IF_EXCEPTION(scope, false);
    10831083            }
     
    10881088            RETURN_IF_EXCEPTION(scope, false);
    10891089            if (value) {
    1090                 target->putDirectIndex(exec, targetOffset + i, value);
     1090                target->putDirectIndex(exec, targetOffset + i, value, 0, PutDirectIndexShouldThrow);
    10911091                RETURN_IF_EXCEPTION(scope, false);
    10921092            }
  • trunk/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp

    r207023 r207178  
    118118    SparseArrayEntry& entry = result.iterator->value;
    119119
    120     // To save a separate find & add, we first always add to the sparse map.
    121     // In the uncommon case that this is a new property, and the array is not
    122     // extensible, this is not the right thing to have done - so remove again.
    123     if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isStructureExtensible()) {
    124         remove(result.iterator);
    125         return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
     120    if (mode != PutDirectIndexLikePutDirect && !array->isStructureExtensible()) {
     121        // To save a separate find & add, we first always add to the sparse map.
     122        // In the uncommon case that this is a new property, and the array is not
     123        // extensible, this is not the right thing to have done - so remove again.
     124        if (result.isNewEntry) {
     125            remove(result.iterator);
     126            return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
     127        }
     128        if (entry.attributes & ReadOnly)
     129            return reject(exec, mode == PutDirectIndexShouldThrow, ReadonlyPropertyWriteError);
    126130    }
    127 
    128131    entry.attributes = attributes;
    129132    entry.set(exec->vm(), this, value);
Note: See TracChangeset for help on using the changeset viewer.