Changeset 288066 in webkit


Ignore:
Timestamp:
Jan 15, 2022 1:35:01 PM (6 months ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Fix Date functions' argument coercion
https://bugs.webkit.org/show_bug.cgi?id=235271

Reviewed by Alexey Shvayka.

JSTests:

  • test262/expectations.yaml:

Source/JavaScriptCore:

Even if the input Date is NaN or the result looks like NaN, we need to coerce passed
arguments to Number[1] since it has observable side effect.

[1]: https://github.com/tc39/ecma262/pull/2136

  • runtime/DatePrototype.cpp:

(JSC::applyToNumbersToTrashedArguments):
(JSC::fillStructuresUsingTimeArgs):
(JSC::fillStructuresUsingDateArgs):
(JSC::setNewValueFromTimeArgs):
(JSC::setNewValueFromDateArgs):

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r288065 r288066  
     12022-01-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Fix Date functions' argument coercion
     4        https://bugs.webkit.org/show_bug.cgi?id=235271
     5
     6        Reviewed by Alexey Shvayka.
     7
     8        * test262/expectations.yaml:
     9
    1102022-01-15  Yusuke Suzuki  <ysuzuki@apple.com>
    211
  • trunk/JSTests/test262/expectations.yaml

    r288062 r288066  
    607607  default: 'Test262Error: order of operations / precision in MakeTime Expected SameValue(«NaN», «29312») to be true'
    608608  strict mode: 'Test262Error: order of operations / precision in MakeTime Expected SameValue(«NaN», «29312») to be true'
    609 test/built-ins/Date/prototype/setDate/arg-coercion-order.js:
    610   default: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    611   strict mode: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    612 test/built-ins/Date/prototype/setHours/arg-coercion-order.js:
    613   default: 'Test262Error: Expected [] and [valueOf hour, valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    614   strict mode: 'Test262Error: Expected [] and [valueOf hour, valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    615 test/built-ins/Date/prototype/setMilliseconds/arg-coercion-order.js:
    616   default: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    617   strict mode: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    618 test/built-ins/Date/prototype/setMinutes/arg-coercion-order.js:
    619   default: 'Test262Error: Expected [] and [valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    620   strict mode: 'Test262Error: Expected [] and [valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    621 test/built-ins/Date/prototype/setMonth/arg-coercion-order.js:
    622   default: 'Test262Error: Expected [] and [valueOf month, valueOf date] to have the same contents. '
    623   strict mode: 'Test262Error: Expected [] and [valueOf month, valueOf date] to have the same contents. '
    624 test/built-ins/Date/prototype/setSeconds/arg-coercion-order.js:
    625   default: 'Test262Error: Expected [] and [valueOf sec, valueOf ms] to have the same contents. '
    626   strict mode: 'Test262Error: Expected [] and [valueOf sec, valueOf ms] to have the same contents. '
    627 test/built-ins/Date/prototype/setUTCDate/arg-coercion-order.js:
    628   default: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    629   strict mode: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    630 test/built-ins/Date/prototype/setUTCHours/arg-coercion-order.js:
    631   default: 'Test262Error: Expected [] and [valueOf hour, valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    632   strict mode: 'Test262Error: Expected [] and [valueOf hour, valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    633 test/built-ins/Date/prototype/setUTCMilliseconds/arg-coercion-order.js:
    634   default: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    635   strict mode: 'Test262Error: ToNumber invoked exactly once Expected SameValue(«0», «1») to be true'
    636 test/built-ins/Date/prototype/setUTCMinutes/arg-coercion-order.js:
    637   default: 'Test262Error: Expected [] and [valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    638   strict mode: 'Test262Error: Expected [] and [valueOf min, valueOf sec, valueOf ms] to have the same contents. '
    639 test/built-ins/Date/prototype/setUTCMonth/arg-coercion-order.js:
    640   default: 'Test262Error: Expected [] and [valueOf month, valueOf date] to have the same contents. '
    641   strict mode: 'Test262Error: Expected [] and [valueOf month, valueOf date] to have the same contents. '
    642 test/built-ins/Date/prototype/setUTCSeconds/arg-coercion-order.js:
    643   default: 'Test262Error: Expected [] and [valueOf sec, valueOf ms] to have the same contents. '
    644   strict mode: 'Test262Error: Expected [] and [valueOf sec, valueOf ms] to have the same contents. '
    645609test/built-ins/Function/internals/Construct/derived-return-val-realm.js:
    646610  default: 'Test262Error: Expected a TypeError but got a different error constructor with the same name'
  • trunk/Source/JavaScriptCore/ChangeLog

    r288065 r288066  
     12022-01-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Fix Date functions' argument coercion
     4        https://bugs.webkit.org/show_bug.cgi?id=235271
     5
     6        Reviewed by Alexey Shvayka.
     7
     8        Even if the input Date is NaN or the result looks like NaN, we need to coerce passed
     9        arguments to Number[1] since it has observable side effect.
     10
     11        [1]: https://github.com/tc39/ecma262/pull/2136
     12
     13        * runtime/DatePrototype.cpp:
     14        (JSC::applyToNumbersToTrashedArguments):
     15        (JSC::fillStructuresUsingTimeArgs):
     16        (JSC::fillStructuresUsingDateArgs):
     17        (JSC::setNewValueFromTimeArgs):
     18        (JSC::setNewValueFromDateArgs):
     19
    1202022-01-15  Yusuke Suzuki  <ysuzuki@apple.com>
    221
  • trunk/Source/JavaScriptCore/runtime/DatePrototype.cpp

    r286994 r288066  
    110110}
    111111
     112
     113static void applyToNumbersToTrashedArguments(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned maxArgs)
     114{
     115    VM& vm = globalObject->vm();
     116    auto scope = DECLARE_THROW_SCOPE(vm);
     117
     118    unsigned numArgs = std::min<unsigned>(callFrame->argumentCount(), maxArgs);
     119    for (unsigned index = 0; index < numArgs; ++index) {
     120        callFrame->uncheckedArgument(index).toNumber(globalObject);
     121        RETURN_IF_EXCEPTION(scope, void());
     122    }
     123}
     124
    112125// Converts a list of arguments sent to a Date member function into milliseconds, updating
    113126// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
    114127//
    115128// Format of member function: f([hour,] [min,] [sec,] [ms])
    116 static bool fillStructuresUsingTimeArgs(JSGlobalObject* globalObject, CallFrame* callFrame, int maxArgs, double* ms, GregorianDateTime* t)
     129static bool fillStructuresUsingTimeArgs(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned maxArgs, double* ms, GregorianDateTime* t)
    117130{
    118131    VM& vm = globalObject->vm();
     
    120133
    121134    double milliseconds = 0;
    122     bool ok = true;
    123     int idx = 0;
    124     int numArgs = callFrame->argumentCount();
    125    
    126     // JS allows extra trailing arguments -- ignore them
    127     if (numArgs > maxArgs)
    128         numArgs = maxArgs;
     135    unsigned idx = 0;
     136    unsigned numArgs = std::min<unsigned>(callFrame->argumentCount(), maxArgs);
    129137
    130138    // hours
     
    133141        double hours = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    134142        RETURN_IF_EXCEPTION(scope, false);
    135         ok = std::isfinite(hours);
    136143        milliseconds += hours * msPerHour;
    137144    }
    138145
    139146    // minutes
    140     if (maxArgs >= 3 && idx < numArgs && ok) {
     147    if (maxArgs >= 3 && idx < numArgs) {
    141148        t->setMinute(0);
    142149        double minutes = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    143150        RETURN_IF_EXCEPTION(scope, false);
    144         ok = std::isfinite(minutes);
    145151        milliseconds += minutes * msPerMinute;
    146152    }
    147    
     153
    148154    // seconds
    149     if (maxArgs >= 2 && idx < numArgs && ok) {
     155    if (maxArgs >= 2 && idx < numArgs) {
    150156        t->setSecond(0);
    151157        double seconds = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    152158        RETURN_IF_EXCEPTION(scope, false);
    153         ok = std::isfinite(seconds);
    154159        milliseconds += seconds * msPerSecond;
    155160    }
    156    
    157     if (!ok)
    158         return false;
    159        
     161
    160162    // milliseconds
    161163    if (idx < numArgs) {
    162164        double millis = callFrame->uncheckedArgument(idx).toIntegerPreserveNaN(globalObject);
    163165        RETURN_IF_EXCEPTION(scope, false);
    164         ok = std::isfinite(millis);
    165166        milliseconds += millis;
    166167    } else
    167168        milliseconds += *ms;
    168    
     169
    169170    *ms = milliseconds;
    170     return ok;
     171    return std::isfinite(milliseconds);
    171172}
    172173
     
    175176//
    176177// Format of member function: f([years,] [months,] [days])
    177 static bool fillStructuresUsingDateArgs(JSGlobalObject* globalObject, CallFrame* callFrame, int maxArgs, double *ms, GregorianDateTime *t)
    178 {
    179     VM& vm = globalObject->vm();
    180     auto scope = DECLARE_THROW_SCOPE(vm);
    181 
    182     int idx = 0;
     178static bool fillStructuresUsingDateArgs(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned maxArgs, double *ms, GregorianDateTime *t)
     179{
     180    VM& vm = globalObject->vm();
     181    auto scope = DECLARE_THROW_SCOPE(vm);
     182
    183183    bool ok = true;
    184     int numArgs = callFrame->argumentCount();
    185  
    186     // JS allows extra trailing arguments -- ignore them
    187     if (numArgs > maxArgs)
    188         numArgs = maxArgs;
     184    unsigned idx = 0;
     185    unsigned numArgs = std::min<unsigned>(callFrame->argumentCount(), maxArgs);
    189186 
    190187    // years
     
    192189        double years = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    193190        RETURN_IF_EXCEPTION(scope, false);
    194         ok = std::isfinite(years);
     191        ok = (ok && std::isfinite(years));
    195192        t->setYear(toInt32(years));
    196193    }
    197194    // months
    198     if (maxArgs >= 2 && idx < numArgs && ok) {
     195    if (maxArgs >= 2 && idx < numArgs) {
    199196        double months = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    200197        RETURN_IF_EXCEPTION(scope, false);
    201         ok = std::isfinite(months);
     198        ok = (ok && std::isfinite(months));
    202199        t->setMonth(toInt32(months));
    203200    }
    204201    // days
    205     if (idx < numArgs && ok) {
     202    if (idx < numArgs) {
    206203        double days = callFrame->uncheckedArgument(idx++).toIntegerPreserveNaN(globalObject);
    207204        RETURN_IF_EXCEPTION(scope, false);
    208         ok = std::isfinite(days);
     205        ok = (ok && std::isfinite(days));
    209206        t->setMonthDay(0);
    210207        *ms += days * msPerDay;
     
    669666}
    670667
    671 static EncodedJSValue setNewValueFromTimeArgs(JSGlobalObject* globalObject, CallFrame* callFrame, int numArgsToUse, WTF::TimeType inputTimeType)
     668static EncodedJSValue setNewValueFromTimeArgs(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned numArgsToUse, WTF::TimeType inputTimeType)
    672669{
    673670    VM& vm = globalObject->vm();
     
    683680
    684681    if (!callFrame->argumentCount() || std::isnan(milli)) {
     682        applyToNumbersToTrashedArguments(globalObject, callFrame, numArgsToUse);
     683        RETURN_IF_EXCEPTION(scope, { });
    685684        thisDateObj->setInternalNumber(PNaN);
    686685        return JSValue::encode(jsNaN());
     
    693692        ? thisDateObj->gregorianDateTimeUTC(cache)
    694693        : thisDateObj->gregorianDateTime(cache);
    695     if (!other)
    696         return JSValue::encode(jsNaN());
     694    if (!other) {
     695        applyToNumbersToTrashedArguments(globalObject, callFrame, numArgsToUse);
     696        RETURN_IF_EXCEPTION(scope, { });
     697        return JSValue::encode(jsNaN());
     698    }
    697699
    698700    GregorianDateTime gregorianDateTime(*other);
    699701    bool success = fillStructuresUsingTimeArgs(globalObject, callFrame, numArgsToUse, &ms, &gregorianDateTime);
    700     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     702    RETURN_IF_EXCEPTION(scope, { });
    701703    if (!success) {
    702704        thisDateObj->setInternalNumber(PNaN);
     
    710712}
    711713
    712 static EncodedJSValue setNewValueFromDateArgs(JSGlobalObject* globalObject, CallFrame* callFrame, int numArgsToUse, WTF::TimeType inputTimeType)
     714static EncodedJSValue setNewValueFromDateArgs(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned numArgsToUse, WTF::TimeType inputTimeType)
    713715{
    714716    VM& vm = globalObject->vm();
     
    722724
    723725    if (!callFrame->argumentCount()) {
     726        applyToNumbersToTrashedArguments(globalObject, callFrame, numArgsToUse);
     727        RETURN_IF_EXCEPTION(scope, { });
    724728        thisDateObj->setInternalNumber(PNaN);
    725729        return JSValue::encode(jsNaN());
     
    737741            ? thisDateObj->gregorianDateTimeUTC(cache)
    738742            : thisDateObj->gregorianDateTime(cache);
    739         if (!other)
     743        if (!other) {
     744            applyToNumbersToTrashedArguments(globalObject, callFrame, numArgsToUse);
     745            RETURN_IF_EXCEPTION(scope, { });
    740746            return JSValue::encode(jsNaN());
     747        }
    741748        gregorianDateTime = *other;
    742749    }
    743750   
    744751    bool success = fillStructuresUsingDateArgs(globalObject, callFrame, numArgsToUse, &ms, &gregorianDateTime);
    745     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     752    RETURN_IF_EXCEPTION(scope, { });
    746753    if (!success) {
    747754        thisDateObj->setInternalNumber(PNaN);
Note: See TracChangeset for help on using the changeset viewer.