Bug 141115 - new Date(NaN).toJSON() must return null instead of throwing a TypeError
Summary: new Date(NaN).toJSON() must return null instead of throwing a TypeError
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Jordan Harband
URL: https://es5.github.io/#x15.9.5.44
Keywords: ES5, InRadar
Depends on:
Blocks:
 
Reported: 2015-01-31 04:59 PST by Claude Pache
Modified: 2015-08-27 18:53 PDT (History)
8 users (show)

See Also:


Attachments
Patch (3.69 KB, patch)
2015-07-19 14:45 PDT, Jordan Harband
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Claude Pache 2015-01-31 04:59:55 PST
When the toJSON method is applied to an invalid date, it must return null, and not throwing a TypeError.

Note that this behaviour is different from the toISOString method.

For reference, see [ES5.1 Date.prototype.toJSON], steps 2 and 3.

[ES5.1 Date.prototype.toJSON]: http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5.44
Comment 1 Jordan Harband 2015-07-18 17:29:11 PDT
It'd be nice to fix this one - Safari/WebKit seem to be skipping step 3.
Comment 2 Jordan Harband 2015-07-19 14:45:58 PDT
Created attachment 257066 [details]
Patch
Comment 3 Yusuke Suzuki 2015-07-19 15:20:19 PDT
Comment on attachment 257066 [details]
Patch

r=me
Comment 4 Darin Adler 2015-07-19 15:37:44 PDT
Comment on attachment 257066 [details]
Patch

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

> Source/JavaScriptCore/runtime/DatePrototype.cpp:1076
> +    JSValue timeValue = object->toPrimitive(exec, PreferNumber);

This patch seems wrong.

If "this" has a valueOf function, the code will call that function, but will ignore the value the function returns except for checking it to see if it’s infinity or NaN. I don’t think that’s correct behavior.

Is that really the behavior the specification calls for? If so, why?
Comment 5 Jordan Harband 2015-07-19 15:40:05 PDT
Absolutely it is. It's specifically to catch the case that WebKit is buggy here on: when toISOString() would throw, toJSON should NOT throw, but should return `null`.
Comment 6 Jordan Harband 2015-07-19 15:40:47 PDT
Put another way, serializing an object to JSON should ideally never cause it to throw, but you can't serialize an invalid date to JSON in WebKit - because it throws (incorrectly).
Comment 7 Darin Adler 2015-07-19 15:44:01 PDT
OK, that sounds wrong.

This will work with the built in toISOString function.

But note that we intentionally call whatever toISOString function is present, which could be any arbitrary function. How can we predict what toISOString will do without calling it? It could even be a function that returns different values when you call it multiple times.

I’m pretty sure the right way to handle this is to detect that toISOString tried to throw an exception, and then clear the exception and return null. Not to try to preflight it, which can’t be done reliably.
Comment 8 Yusuke Suzuki 2015-07-19 15:44:07 PDT
Comment on attachment 257066 [details]
Patch

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

>> Source/JavaScriptCore/runtime/DatePrototype.cpp:1076
>> +    JSValue timeValue = object->toPrimitive(exec, PreferNumber);
> 
> This patch seems wrong.
> 
> If "this" has a valueOf function, the code will call that function, but will ignore the value the function returns except for checking it to see if it’s infinity or NaN. I don’t think that’s correct behavior.
> 
> Is that really the behavior the specification calls for? If so, why?

This behavior is actually specified here.
http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5.44

1. Let O be the result of calling ToObject, giving it the this value as its argument.
2. Let tv be ToPrimitive(O, hint Number).
3. If tv is a Number and is not finite, return null.
4. Let toISO be the result of calling the [[Get]] internal method of O with argument "toISOString".
5. If IsCallable(toISO) is false, throw a TypeError exception.
6. Return the result of calling the [[Call]] internal method of toISO with O as the this value and an empty argument list.

And it is the same in the ES6 spec.
http://ecma-international.org/ecma-262/6.0/#sec-date.prototype.tojso

tv is just used to check that the toPrimitive result value is finite or not.

I think this is becacuse Date#toJSON is defined as the generic function. The spec notes that

> NOTE 2 The toJSON function is intentionally generic; it does not require that its this value be a Date object. Therefore, it can be transferred to other kinds of objects for use as a method. However, it does require that any such object have a toISOString method.

So to check the held value, instead of extracting the value of Date's private field, it calls `toPrimitive` to extract it from the possibly date object.
Comment 9 Darin Adler 2015-07-19 15:46:10 PDT
OK, that is a strange way to specify it, but I accept that it’s what the standard calls for.
Comment 10 WebKit Commit Bot 2015-07-19 16:11:25 PDT
Comment on attachment 257066 [details]
Patch

Clearing flags on attachment: 257066

Committed r187016: <http://trac.webkit.org/changeset/187016>
Comment 11 WebKit Commit Bot 2015-07-19 16:11:29 PDT
All reviewed patches have been landed.  Closing bug.
Comment 12 Radar WebKit Bug Importer 2015-08-27 18:53:12 PDT
<rdar://problem/22468732>