Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BalanceTimeDuration: CreateTimeDurationRecord can create too large duration values #2785

Closed
anba opened this issue Feb 23, 2024 · 5 comments · Fixed by #2839
Closed

BalanceTimeDuration: CreateTimeDurationRecord can create too large duration values #2785

anba opened this issue Feb 23, 2024 · 5 comments · Fixed by #2839
Assignees
Labels
editorial spec-text Specification text involved

Comments

@anba
Copy link
Contributor

anba commented Feb 23, 2024

Mentioned in review for #2727.

The final CreateTimeDurationRecord in BalanceTimeDuration can create duration values which are larger than the maximum allowed duration.

Test case:

let d = Temporal.Duration.from({
  seconds: 2**53 - 1,
  nanoseconds: 999_999_999,
});
d.round({
  largestUnit: "nanoseconds",
});

BalanceTimeDuration is called with norm = {[[TotalNanoseconds]]: 9007199254740991999999999} (the largest possible duration value). The final step in BalanceTimeDuration calls CreateTimeDurationRecord with nanoseconds = 9007199254740991999999999, which performs:

  1. Assert: ! IsValidDuration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is true.
  2. Return the Record { [[Days]]: ℝ(𝔽(days)), [[Hours]]: ℝ(𝔽(hours)), [[Minutes]]: ℝ(𝔽(minutes)), [[Seconds]]: ℝ(𝔽(seconds)), [[Milliseconds]]: ℝ(𝔽(milliseconds)), [[Microseconds]]: ℝ(𝔽(microseconds)), [[Nanoseconds]]: ℝ(𝔽(nanoseconds)) }.

The assertion in step 1 passes, because all computations are performed using mathematical values. But ℝ(𝔽(nanoseconds)) in step 2 performs ℝ(𝔽(9007199254740991999999999)) = 9007199254740992000000000. And 9007199254740992000000000 exceeds the maximum allowed duration value.

@ptomato
Copy link
Collaborator

ptomato commented Feb 24, 2024

I went through the comment threads on #2727 and I guess you are referring to #2727 (comment)? Unfortunately I must have missed that reply at the time.

I agree, we'll just have to make BalanceTimeDuration fallible again, unfortunately.

@ptomato
Copy link
Collaborator

ptomato commented Feb 24, 2024

Oh, ugh. It's not just a question of adding "If IsValidDuration(0, 0, 0, days, ..., nanoseconds) is false, throw a RangeError exception" to BalanceTimeDuration, because as you pointed out, the duration in the test case (which is already in test262 in test/built-ins/Temporal/Duration/prototype/round/out-of-range-when-converting-from-normalized-duration.js) actually is a valid duration according to IsValidDuration.

I'm thinking of replacing step 6 in IsValidDuration with this:

  1. Let normalizedSeconds be ℝ(𝔽(days)) × 86,400 + ℝ(𝔽(hours)) × 3600 + ℝ(𝔽(minutes)) × 60 + ℝ(𝔽(seconds)) + ℝ(𝔽(milliseconds)) × 10-3 + ℝ(𝔽(microseconds)) × 10-6 + ℝ(𝔽(nanoseconds)) × 10-9.

That seems correct because the ℝ(𝔽(...)) values are what will be retrieved from the Duration slots if the user does any subsequent calculations with that Duration.

But you probably have thought about this a lot more than I have. Do you know of any cases where replacing the above line would actually allow some cases that would currently be disallowed? Do you have any alternative suggestions?

@ptomato ptomato self-assigned this Feb 24, 2024
@ptomato ptomato added spec-text Specification text involved editorial labels Feb 24, 2024
ptomato added a commit to ptomato/test262 that referenced this issue Feb 24, 2024
This test isn't testing what the assertion message previously said it was
testing. The integer is allowed to be unsafe, but in this case its
float64-representation is out of range.

See: tc39/proposal-temporal#2785
@anba
Copy link
Contributor Author

anba commented Feb 26, 2024

I think that approach should work. The ℝ(𝔽(...)) conversions are only needed for milliseconds, microseconds, and nanoseconds, because too large values for all other time units will be handled through the abs(normalizedSeconds) ≥ 2**53 check in IsValidDuration.

ptomato added a commit that referenced this issue Mar 12, 2024
There was an edge case, spotted by Anba, where floating-point rounding at
the point of conversion from normalized form to Duration storage form, in
BalanceTimeDuration, can result in a Duration storage form that fails
assertions.

For example, when a normalized time duration is the maximum possible value
{ [[TotalNanoseconds]]: 9007199254740991999999999 }, and
BalanceTimeDuration is called with largestUnit nanoseconds.

This is already covered by test262 tests.

Closes: #2785
@Ms2ger Ms2ger closed this as completed in 1643cc6 Mar 12, 2024
Ms2ger pushed a commit to ptomato/test262 that referenced this issue Apr 3, 2024
This test isn't testing what the assertion message previously said it was
testing. The integer is allowed to be unsafe, but in this case its
float64-representation is out of range.

See: tc39/proposal-temporal#2785
Ms2ger pushed a commit to tc39/test262 that referenced this issue Apr 3, 2024
This test isn't testing what the assertion message previously said it was
testing. The integer is allowed to be unsafe, but in this case its
float64-representation is out of range.

See: tc39/proposal-temporal#2785
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Apr 16, 2024
… r=mgaudet

BalanceTimeDuration is fallible, cf. <tc39/proposal-temporal#2785>.

Depends on D204393

Differential Revision: https://phabricator.services.mozilla.com/D204394
@anba
Copy link
Contributor Author

anba commented Apr 17, 2024

Commit 1643cc6 only changed IsValidDuration to correctly reject too large duration values, but CreateTimeDurationRecord in BalanceTimeDuration is still incorrectly marked as infallible.

@ptomato
Copy link
Collaborator

ptomato commented Apr 17, 2024

I'll address that in the next editorial PR, thanks.

@ptomato ptomato reopened this Apr 17, 2024
ErichDonGubler pushed a commit to ErichDonGubler/firefox that referenced this issue Apr 17, 2024
… r=mgaudet

BalanceTimeDuration is fallible, cf. <tc39/proposal-temporal#2785>.

Depends on D204393

Differential Revision: https://phabricator.services.mozilla.com/D204394
ptomato added a commit that referenced this issue May 14, 2024
Commit 1643cc6 only changed IsValidDuration to correctly reject too-large
duration values, but the other half was that BalanceTimeDuration needs to
be able to throw when that happens.

BalanceTimeDuration can throw due to floating-point rounding error if the
normalized time duration could be nearby the limit and largestUnit is
milliseconds, microseconds, or nanoseconds.

Closes: #2785
Ms2ger pushed a commit that referenced this issue May 15, 2024
Commit 1643cc6 only changed IsValidDuration to correctly reject too-large
duration values, but the other half was that BalanceTimeDuration needs to
be able to throw when that happens.

BalanceTimeDuration can throw due to floating-point rounding error if the
normalized time duration could be nearby the limit and largestUnit is
milliseconds, microseconds, or nanoseconds.

Closes: #2785
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
editorial spec-text Specification text involved
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants