Changeset 207341 in webkit


Ignore:
Timestamp:
Oct 14, 2016 8:58:16 AM (8 years ago)
Author:
mark.lam@apple.com
Message:

JSON.parse should not modify frozen objects.
https://bugs.webkit.org/show_bug.cgi?id=163430

Reviewed by Saam Barati.

JSTests:

  • stress/json-parse-on-frozen-object.js: Added.

Source/JavaScriptCore:

The ES6 spec for JSON.parse (https://tc39.github.io/ecma262/#sec-json.parse and
https://tc39.github.io/ecma262/#sec-internalizejsonproperty) states that it uses
CreateDataProperty() (https://tc39.github.io/ecma262/#sec-createdataproperty) to
set values returned by a reviver. 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."

Note: CreateDataProperty() will not throw a TypeError.

Since the properties of frozen objects are not extensible, not configurable, and
not writeable, JSON.parse should fail to write to any frozen objects. Similarly,
JSON.parse should fail to delete properties in frozen objects.

In JSON.parse(), we previously write to array elements using the form of
putDirectIndex() that uses mode PutDirectIndexLikePutDirect. This makes it so
that the write (i.e. put) is always successful. We've now fixed this to use
PutDirectIndexShouldNotThrow mode instead, which will fail to put the element if
the array is not writeable.

Also changed Walker::walk() to use the version of methodTable() that takes a VM&
since the VM& is already available.

  • runtime/JSONObject.cpp:

(JSC::Walker::walk):

Location:
trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207334 r207341  
     12016-10-14  Mark Lam  <mark.lam@apple.com>
     2
     3        JSON.parse should not modify frozen objects.
     4        https://bugs.webkit.org/show_bug.cgi?id=163430
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/json-parse-on-frozen-object.js: Added.
     9
    1102016-10-14  Joseph Pecoraro  <pecoraro@apple.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r207334 r207341  
     12016-10-14  Mark Lam  <mark.lam@apple.com>
     2
     3        JSON.parse should not modify frozen objects.
     4        https://bugs.webkit.org/show_bug.cgi?id=163430
     5
     6        Reviewed by Saam Barati.
     7
     8        The ES6 spec for JSON.parse (https://tc39.github.io/ecma262/#sec-json.parse and
     9        https://tc39.github.io/ecma262/#sec-internalizejsonproperty) states that it uses
     10        CreateDataProperty() (https://tc39.github.io/ecma262/#sec-createdataproperty) to
     11        set values returned by a reviver.  The spec for CreateDataPropertyOrThrow states:
     12
     13        "This abstract operation creates a property whose attributes are set to the same
     14        defaults used for properties created by the ECMAScript language assignment
     15        operator. Normally, the property will not already exist. If it does exist and is
     16        not configurable or if O is not extensible, [[DefineOwnProperty]] will return
     17        false."
     18
     19        Note: CreateDataProperty() will not throw a TypeError.
     20
     21        Since the properties of frozen objects are not extensible, not configurable, and
     22        not writeable, JSON.parse should fail to write to any frozen objects.  Similarly,
     23        JSON.parse should fail to delete properties in frozen objects.
     24
     25        In JSON.parse(), we previously write to array elements using the form of
     26        putDirectIndex() that uses mode PutDirectIndexLikePutDirect.  This makes it so
     27        that the write (i.e. put) is always successful.  We've now fixed this to use
     28        PutDirectIndexShouldNotThrow mode instead, which will fail to put the element if
     29        the array is not writeable.
     30
     31        Also changed Walker::walk() to use the version of methodTable() that takes a VM&
     32        since the VM& is already available.
     33
     34        * runtime/JSONObject.cpp:
     35        (JSC::Walker::walk):
     36
    1372016-10-14  Joseph Pecoraro  <pecoraro@apple.com>
    238
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r206386 r207341  
    632632                else {
    633633                    PropertySlot slot(array, PropertySlot::InternalMethodType::Get);
    634                     if (array->methodTable()->getOwnPropertySlotByIndex(array, m_exec, index, slot))
     634                    if (array->methodTable(vm)->getOwnPropertySlotByIndex(array, m_exec, index, slot))
    635635                        inValue = slot.getValue(m_exec, index);
    636636                    else
     
    650650                JSValue filteredValue = callReviver(array, jsString(m_exec, String::number(indexStack.last())), outValue);
    651651                if (filteredValue.isUndefined())
    652                     array->methodTable()->deletePropertyByIndex(array, m_exec, indexStack.last());
     652                    array->methodTable(vm)->deletePropertyByIndex(array, m_exec, indexStack.last());
    653653                else
    654                     array->putDirectIndex(m_exec, indexStack.last(), filteredValue);
     654                    array->putDirectIndex(m_exec, indexStack.last(), filteredValue, 0, PutDirectIndexShouldNotThrow);
    655655                RETURN_IF_EXCEPTION(scope, JSValue());
    656656                indexStack.last()++;
     
    668668                indexStack.append(0);
    669669                propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings));
    670                 object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
     670                object->methodTable(vm)->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
    671671                RETURN_IF_EXCEPTION(scope, JSValue());
    672672            }
     
    685685                }
    686686                PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
    687                 if (object->methodTable()->getOwnPropertySlot(object, m_exec, properties[index], slot))
     687                if (object->methodTable(vm)->getOwnPropertySlot(object, m_exec, properties[index], slot))
    688688                    inValue = slot.getValue(m_exec, properties[index]);
    689689                else
     
    706706                JSValue filteredValue = callReviver(object, jsString(m_exec, prop.string()), outValue);
    707707                if (filteredValue.isUndefined())
    708                     object->methodTable()->deleteProperty(object, m_exec, prop);
     708                    object->methodTable(vm)->deleteProperty(object, m_exec, prop);
    709709                else
    710                     object->methodTable()->put(object, m_exec, prop, filteredValue, slot);
     710                    object->methodTable(vm)->put(object, m_exec, prop, filteredValue, slot);
    711711                RETURN_IF_EXCEPTION(scope, JSValue());
    712712                indexStack.last()++;
     
    732732    JSObject* finalHolder = constructEmptyObject(m_exec);
    733733    PutPropertySlot slot(finalHolder);
    734     finalHolder->methodTable()->put(finalHolder, m_exec, vm.propertyNames->emptyIdentifier, outValue, slot);
     734    finalHolder->methodTable(vm)->put(finalHolder, m_exec, vm.propertyNames->emptyIdentifier, outValue, slot);
    735735    return callReviver(finalHolder, jsEmptyString(m_exec), outValue);
    736736}
Note: See TracChangeset for help on using the changeset viewer.