Bug 188378 - Date.UTC should not return NaN with only Year param
Summary: Date.UTC should not return NaN with only Year param
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: Safari 11
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2018-08-07 04:37 PDT by isol2
Modified: 2018-08-14 09:31 PDT (History)
9 users (show)

See Also:


Attachments
Patch (5.22 KB, patch)
2018-08-10 08:24 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (5.24 KB, patch)
2018-08-10 08:27 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (5.25 KB, patch)
2018-08-10 08:28 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (5.63 KB, patch)
2018-08-10 10:06 PDT, Yusuke Suzuki
keith_miller: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description isol2 2018-08-07 04:37:49 PDT
Hi everyone,
there is a inconsistency on JSC when we try to get Date.UTC passing only the year param.
According to ES6 specs (https://www.ecma-international.org/ecma-262/8.0/index.html#sec-date.utc) the year param is required, the others params are optional.

JSC build: 234555
OS: Ubuntu 16.04 x64

Steps to reproduce:
d = Date.UTC(2015);
print(isNaN(d));

d = Date.UTC(2000 + 15, 0);
print(d == 1420070400000);


Actual results:
true
true

Expected results:
false
true

Chakra, V8 and SpiderMonkey works as expected.

cinfuzz
Comment 1 Yusuke Suzuki 2018-08-10 08:24:45 PDT
Created attachment 346904 [details]
Patch
Comment 2 EWS Watchlist 2018-08-10 08:26:02 PDT
Attachment 346904 [details] did not pass style-queue:


ERROR: Source/JavaScriptCore/ChangeLog:8:  Line contains tab character.  [whitespace/tab] [5]
ERROR: Source/JavaScriptCore/ChangeLog:9:  Line contains tab character.  [whitespace/tab] [5]
Total errors found: 2 in 4 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 3 Yusuke Suzuki 2018-08-10 08:27:32 PDT
Created attachment 346905 [details]
Patch
Comment 4 Yusuke Suzuki 2018-08-10 08:28:27 PDT
Created attachment 346906 [details]
Patch
Comment 5 EWS Watchlist 2018-08-10 09:46:36 PDT
Comment on attachment 346906 [details]
Patch

Attachment 346906 [details] did not pass jsc-ews (mac):
Output: https://webkit-queues.webkit.org/results/8819741

New failing tests:
ChakraCore.yaml/ChakraCore/test/Date/dateutc.js.default
apiTests
Comment 6 Yusuke Suzuki 2018-08-10 10:06:15 PDT
Created attachment 346908 [details]
Patch
Comment 7 Keith Miller 2018-08-10 10:32:01 PDT
Comment on attachment 346908 [details]
Patch

r=me. Does this fix any test262 tests?
Comment 8 Yusuke Suzuki 2018-08-10 10:38:43 PDT
(In reply to Keith Miller from comment #7)
> Comment on attachment 346908 [details]
> Patch
> 
> r=me. Does this fix any test262 tests?

test/built-ins/Date/UTC/return-value.js has passed! I've added it :D
Comment 9 Yusuke Suzuki 2018-08-10 10:42:39 PDT
Committed r234763: <https://trac.webkit.org/changeset/234763>
Comment 10 Radar WebKit Bug Importer 2018-08-10 10:43:18 PDT
<rdar://problem/43147473>
Comment 11 Darin Adler 2018-08-14 09:31:39 PDT
Comment on attachment 346908 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=346908&action=review

> Source/JavaScriptCore/runtime/DateConstructor.cpp:94
> +    double doubleArguments[7] {
> +        0, 0, 1, 0, 0, 0, 0
> +    };

Reads nicely on a single line.

> Source/JavaScriptCore/runtime/DateConstructor.cpp:95
> +    unsigned numberOfUsedArguments = std::max(std::min<unsigned>(7U, args.size()), 1U);

I like to write clamping expressions in sequence like this:

    unsigned numberOfUsedArguments = std::max(1U, std::min<unsigned>(args.size(), 7U));

> Source/JavaScriptCore/runtime/DateConstructor.cpp:101
> +        if (!std::isfinite(doubleArguments[i]) || (doubleArguments[i] > INT_MAX) || (doubleArguments[i] < INT_MIN))

This can be done more efficiently without an explicit isfinite check:

    if (!(doubleArguments[i] >= std::numeric_limits<int>::min() && doubleArguments[i] <= std::numeric_limits<int>::max()))

By doing the checks in this fashion, NaN and both infinities are handled naturally without any explicit check.

> Source/JavaScriptCore/runtime/DateConstructor.cpp:106
>      int year = JSC::toInt32(doubleArguments[0]);

Not new to this patch: I don’t think it is correct to call toInt32 after checking if the value is in range.

I believe this means the range check doesn’t take the rounding done by toInt32 into account and I suspect we will have incorrect results for values right on the edge of the acceptable range. For example, if the value is the maximum integer + 0.1 or the minimum integer - 0.1 it will be treated as NaN, but should not be. Someone should add test cases to cover these edges and then change this to use the correct idiom.

I also suspect that there is a more efficient way to do the JSC::toInt32 operation when we know we don’t want to convert any values outside the 32-bit integer range. For example, maybe std::lround already does the right thing efficiently for that case?

Being more efficient here is not critical, but it would be nice to handle the edges 100% correctly.