Changeset 233918 in webkit


Ignore:
Timestamp:
Jul 18, 2018 11:31:09 AM (6 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] JSON.stringify's replacer should use isArray instead of JSArray checks
https://bugs.webkit.org/show_bug.cgi?id=187755

Reviewed by Mark Lam.

JSTests:

  • stress/json-stringify-gap-calculation-should-be-after-replacer-check.js: Added.

(shouldThrow):
(shouldThrow.string.toString):

  • test262/expectations.yaml:

Source/JavaScriptCore:

JSON.stringify used inherits<JSArray>(vm) to determine whether the given replacer is an array replacer.
But this is wrong. According to the spec, we should use isArray[1], which accepts Proxies. This difference
makes one test262 test failed.

This patch changes the code to using isArray(). And we reorder the evaluations of replacer check and ident space check
to align these checks to the spec's order.

[1]: https://tc39.github.io/ecma262/#sec-json.stringify

  • runtime/JSONObject.cpp:

(JSC::Stringifier::Stringifier):

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r233855 r233918  
     12018-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] JSON.stringify's replacer should use `isArray` instead of JSArray checks
     4        https://bugs.webkit.org/show_bug.cgi?id=187755
     5
     6        Reviewed by Mark Lam.
     7
     8        * stress/json-stringify-gap-calculation-should-be-after-replacer-check.js: Added.
     9        (shouldThrow):
     10        (shouldThrow.string.toString):
     11        * test262/expectations.yaml:
     12
    1132018-07-12  Yusuke Suzuki  <utatane.tea@gmail.com>
    214
  • trunk/JSTests/test262/expectations.yaml

    r233855 r233918  
    10351035  default: 'Test262Error: Expected a Test262Error to be thrown but no exception was thrown at all'
    10361036  strict mode: 'Test262Error: Expected a Test262Error to be thrown but no exception was thrown at all'
    1037 test/built-ins/JSON/stringify/replacer-proxy-revoked.js:
    1038   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    1039   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    10401037test/built-ins/Map/proto-from-ctor-realm.js:
    10411038  default: 'Test262Error: Expected SameValue(«[object Map]», «[object Map]») to be true'
  • trunk/Source/JavaScriptCore/ChangeLog

    r233917 r233918  
     12018-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] JSON.stringify's replacer should use `isArray` instead of JSArray checks
     4        https://bugs.webkit.org/show_bug.cgi?id=187755
     5
     6        Reviewed by Mark Lam.
     7
     8        JSON.stringify used `inherits<JSArray>(vm)` to determine whether the given replacer is an array replacer.
     9        But this is wrong. According to the spec, we should use `isArray`[1], which accepts Proxies. This difference
     10        makes one test262 test failed.
     11
     12        This patch changes the code to using `isArray()`. And we reorder the evaluations of replacer check and ident space check
     13        to align these checks to the spec's order.
     14
     15        [1]: https://tc39.github.io/ecma262/#sec-json.stringify
     16
     17        * runtime/JSONObject.cpp:
     18        (JSC::Stringifier::Stringifier):
     19
    1202018-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
    221
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r233917 r233918  
    227227    auto scope = DECLARE_THROW_SCOPE(vm);
    228228
     229    if (m_replacer.isObject()) {
     230        JSObject* replacerObject = asObject(m_replacer);
     231
     232        m_replacerCallType = CallType::None;
     233        if (!replacerObject->isCallable(vm, m_replacerCallType, m_replacerCallData)) {
     234            bool isArrayReplacer = JSC::isArray(exec, replacerObject);
     235            RETURN_IF_EXCEPTION(scope, );
     236            if (isArrayReplacer) {
     237                m_usingArrayReplacer = true;
     238                unsigned length = replacerObject->get(exec, vm.propertyNames->length).toUInt32(exec);
     239                RETURN_IF_EXCEPTION(scope, );
     240                for (unsigned i = 0; i < length; ++i) {
     241                    JSValue name = replacerObject->get(exec, i);
     242                    RETURN_IF_EXCEPTION(scope, );
     243                    if (name.isObject()) {
     244                        auto* nameObject = jsCast<JSObject*>(name);
     245                        if (!nameObject->inherits<NumberObject>(vm) && !nameObject->inherits<StringObject>(vm))
     246                            continue;
     247                    } else if (!name.isNumber() && !name.isString())
     248                        continue;
     249                    m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec));
     250                    RETURN_IF_EXCEPTION(scope, );
     251                }
     252            }
     253        }
     254    }
     255
     256    scope.release();
    229257    m_gap = gap(exec, space);
    230     if (UNLIKELY(scope.exception()))
    231         return;
    232 
    233     if (!m_replacer.isObject())
    234         return;
    235 
    236     JSObject* replacerObject = asObject(m_replacer);
    237     if (replacerObject->inherits<JSArray>(vm)) {
    238         m_usingArrayReplacer = true;
    239         JSArray* array = jsCast<JSArray*>(replacerObject);
    240         unsigned length = array->get(exec, vm.propertyNames->length).toUInt32(exec);
    241         if (UNLIKELY(scope.exception()))
    242             return;
    243         for (unsigned i = 0; i < length; ++i) {
    244             JSValue name = array->get(exec, i);
    245             if (UNLIKELY(scope.exception()))
    246                 break;
    247 
    248             if (auto* nameObject = jsDynamicCast<JSObject*>(vm, name)) {
    249                 if (!nameObject->inherits<NumberObject>(vm) && !nameObject->inherits<StringObject>(vm))
    250                     continue;
    251             } else if (!name.isNumber() && !name.isString())
    252                 continue;
    253 
    254             m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec));
    255         }
    256         return;
    257     }
    258 
    259     m_replacerCallType = replacerObject->methodTable(vm)->getCallData(replacerObject, m_replacerCallData);
    260258}
    261259
Note: See TracChangeset for help on using the changeset viewer.