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

Properly detect overflow in Instance ± Duration. #44220

Merged
merged 4 commits into from Sep 10, 2017

Conversation

Projects
None yet
7 participants
@kennytm
Member

kennytm commented Aug 31, 2017

Fix #44216.
Fix #42622

The computation Instant::now() + Duration::from_secs(u64::max_value()) now panics. The call receiver.recv_timeout(Duration::from_secs(u64::max_value())), which involves such time addition, will also panic.

The reason #44216 arises is because of an unchecked cast from u64 to i64, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an i64, yet this is rejected because (2⁶³) overflows the i64.

@rust-highfive

This comment has been minimized.

Show comment
Hide comment
@rust-highfive

rust-highfive Aug 31, 2017

Collaborator

r? @alexcrichton

(rust_highfive has picked a reviewer for you, use r? to override)

Collaborator

rust-highfive commented Aug 31, 2017

r? @alexcrichton

(rust_highfive has picked a reviewer for you, use r? to override)

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Aug 31, 2017

Member

@bors: r+

Looks great, thanks!

Member

alexcrichton commented Aug 31, 2017

@bors: r+

Looks great, thanks!

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Aug 31, 2017

Contributor

📌 Commit abc11c3 has been approved by alexcrichton

Contributor

bors commented Aug 31, 2017

📌 Commit abc11c3 has been approved by alexcrichton

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 3, 2017

Contributor

⌛️ Testing commit abc11c3 with merge f2b7ddd...

Contributor

bors commented Sep 3, 2017

⌛️ Testing commit abc11c3 with merge f2b7ddd...

bors added a commit that referenced this pull request Sep 3, 2017

Auto merge of #44220 - kennytm:fix-44216-instance-plus-max-duration-s…
…hould-panic, r=alexcrichton

Properly detect overflow in Instance ± Duration.

Fix #44216.

The computation `Instant::now() + Duration::from_secs(u64::max_value())` now panics. The call `receiver.recv_timeout(Duration::from_secs(u64::max_value()))`, which involves such time addition, will also panic.

The reason #44216 arises is because of an unchecked cast from `u64` to `i64`, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an `i64`, yet this is rejected because (2⁶³) overflows the `i64`.
@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 3, 2017

Contributor

💔 Test failed - status-travis

Contributor

bors commented Sep 3, 2017

💔 Test failed - status-travis

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 3, 2017

Member

armhf-gnu failed, legit.

[01:13:00] failures:
[01:13:00] 
[01:13:00] ---- time::tests::system_time_math stdout ----
[01:13:00] 	thread 'time::tests::system_time_math' panicked at 'overflow when subtracting duration from time', /checkout/src/libcore/option.rs:839:4
[01:13:00] 
[01:13:00] 
[01:13:00] failures:
[01:13:00]     time::tests::system_time_math
[01:13:00] 
[01:13:00] test result: FAILED. 801 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out
[01:13:00] 
[01:13:00] �[m�[m�[31m�[1merror:�[m test failed, to rerun pass '--lib'
Member

kennytm commented Sep 3, 2017

armhf-gnu failed, legit.

[01:13:00] failures:
[01:13:00] 
[01:13:00] ---- time::tests::system_time_math stdout ----
[01:13:00] 	thread 'time::tests::system_time_math' panicked at 'overflow when subtracting duration from time', /checkout/src/libcore/option.rs:839:4
[01:13:00] 
[01:13:00] 
[01:13:00] failures:
[01:13:00]     time::tests::system_time_math
[01:13:00] 
[01:13:00] test result: FAILED. 801 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out
[01:13:00] 
[01:13:00] �[m�[m�[31m�[1merror:�[m test failed, to rerun pass '--lib'
@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 3, 2017

Member

@alexcrichton Failure should be fixed in ef8c204:

diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs
index 5b893505b3..bd96f2133e 100644
--- a/src/libstd/time/mod.rs
+++ b/src/libstd/time/mod.rs
@@ -498,7 +498,7 @@ mod tests {
                 let dur = dur.duration();
                 assert!(a > b);
                 assert_almost_eq!(b + dur, a);
-                assert_almost_eq!(b - dur, a);
+                assert_almost_eq!(a - dur, b);
             }

If I understand correctly, the original test is wrong.

Member

kennytm commented Sep 3, 2017

@alexcrichton Failure should be fixed in ef8c204:

diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs
index 5b893505b3..bd96f2133e 100644
--- a/src/libstd/time/mod.rs
+++ b/src/libstd/time/mod.rs
@@ -498,7 +498,7 @@ mod tests {
                 let dur = dur.duration();
                 assert!(a > b);
                 assert_almost_eq!(b + dur, a);
-                assert_almost_eq!(b - dur, a);
+                assert_almost_eq!(a - dur, b);
             }

If I understand correctly, the original test is wrong.

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Sep 3, 2017

Member

Hm no I don't believe that's the purpose of the test (that's a different equality). I know though that the arm setup has really weird clocks and it's not quite right in qemu, so it's fine to ignore the test there.

Member

alexcrichton commented Sep 3, 2017

Hm no I don't believe that's the purpose of the test (that's a different equality). I know though that the arm setup has really weird clocks and it's not quite right in qemu, so it's fine to ignore the test there.

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 3, 2017

Member

@alexcrichton if the original test is correct that means we assert a ≈ b + dur && a ≈ b - dur? That's only possible if dur ≈ 0, which won't be true especially when the SystemClock::now is "weird".

Do you mean we should revert ef8c204 and just #[cfg] out the test outside of x86?

Member

kennytm commented Sep 3, 2017

@alexcrichton if the original test is correct that means we assert a ≈ b + dur && a ≈ b - dur? That's only possible if dur ≈ 0, which won't be true especially when the SystemClock::now is "weird".

Do you mean we should revert ef8c204 and just #[cfg] out the test outside of x86?

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Sep 5, 2017

Member

Ah sorry no I think I misread and I believe you're right in that this is the intended test! Let's see if this works...

@bors: r+

Member

alexcrichton commented Sep 5, 2017

Ah sorry no I think I misread and I believe you're right in that this is the intended test! Let's see if this works...

@bors: r+

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 5, 2017

Contributor

📌 Commit ef8c204 has been approved by alexcrichton

Contributor

bors commented Sep 5, 2017

📌 Commit ef8c204 has been approved by alexcrichton

@Mark-Simulacrum

This comment has been minimized.

Show comment
Hide comment
@Mark-Simulacrum
Member

Mark-Simulacrum commented Sep 6, 2017

@bors rollup

Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this pull request Sep 6, 2017

Rollup merge of rust-lang#44220 - kennytm:fix-44216-instance-plus-max…
…-duration-should-panic, r=alexcrichton

Properly detect overflow in Instance ± Duration.

Fix rust-lang#44216.

The computation `Instant::now() + Duration::from_secs(u64::max_value())` now panics. The call `receiver.recv_timeout(Duration::from_secs(u64::max_value()))`, which involves such time addition, will also panic.

The reason rust-lang#44216 arises is because of an unchecked cast from `u64` to `i64`, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an `i64`, yet this is rejected because (2⁶³) overflows the `i64`.

bors added a commit that referenced this pull request Sep 6, 2017

bors added a commit that referenced this pull request Sep 6, 2017

@Mark-Simulacrum

This comment has been minimized.

Show comment
Hide comment
@Mark-Simulacrum

Mark-Simulacrum Sep 7, 2017

Member

I suspect that this is the cause of the following failure in the rollup (on armhf-gnu):

@bors r-

[01:11:59] 	thread 'time::tests::system_time_math' panicked at 'overflow when subtracting duration from time', /checkout/src/libcore/option.rs:839:4
[01:11:59] 
[01:11:59] 
[01:11:59] failures:
[01:11:59]     time::tests::system_time_math
[01:11:59] 
[01:11:59] test result: FAILED. 807 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out
Member

Mark-Simulacrum commented Sep 7, 2017

I suspect that this is the cause of the following failure in the rollup (on armhf-gnu):

@bors r-

[01:11:59] 	thread 'time::tests::system_time_math' panicked at 'overflow when subtracting duration from time', /checkout/src/libcore/option.rs:839:4
[01:11:59] 
[01:11:59] 
[01:11:59] failures:
[01:11:59]     time::tests::system_time_math
[01:11:59] 
[01:11:59] test result: FAILED. 807 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out

@kennytm kennytm changed the title from Properly detect overflow in Instance ± Duration. to [WIP] Properly detect overflow in Instance ± Duration. Sep 7, 2017

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 7, 2017

Member

Looks like the actual problem is that time_t on armhf-gnu is 32-bit, so 80 years is too long.

Member

kennytm commented Sep 7, 2017

Looks like the actual problem is that time_t on armhf-gnu is 32-bit, so 80 years is too long.

kennytm added some commits Aug 31, 2017

Properly detect overflow in Instance +/- Duration.
Avoid unchecked cast from `u64` to `i64`. Use `try_into()` for checked
cast. (On Unix, cast to `time_t` instead of `i64`.)

@kennytm kennytm changed the title from [WIP] Properly detect overflow in Instance ± Duration. to Properly detect overflow in Instance ± Duration. Sep 7, 2017

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 7, 2017

Member

@alexcrichton Actual failure cause is found. As stated before, time_t on armhf-gnu is 32-bit, thus won't support a difference more than ~68 years (231 seconds). The two tests below will always fail:

        let eighty_years = second * 60 * 60 * 24 * 365 * 80;
        assert_almost_eq!(a - eighty_years + eighty_years, a);
        assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);

Previously the test passed because the computation is done at i64 and unchecked-cast to time_t as the final step. The a - (800 years) test should overflow.

Currently I disabled these tests when time_t is 32-bit. But would it make more sense we store the system time as i64 unconditionally instead of time_t?


@bors rollup-

Member

kennytm commented Sep 7, 2017

@alexcrichton Actual failure cause is found. As stated before, time_t on armhf-gnu is 32-bit, thus won't support a difference more than ~68 years (231 seconds). The two tests below will always fail:

        let eighty_years = second * 60 * 60 * 24 * 365 * 80;
        assert_almost_eq!(a - eighty_years + eighty_years, a);
        assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);

Previously the test passed because the computation is done at i64 and unchecked-cast to time_t as the final step. The a - (800 years) test should overflow.

Currently I disabled these tests when time_t is 32-bit. But would it make more sense we store the system time as i64 unconditionally instead of time_t?


@bors rollup-

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Sep 7, 2017

Member

@bors: r+

Thanks for the investigation!

We may want to investigate a platform-independent representation of Duration and Instant in the future, yeah, but that's fine to happen in a separate PR.

Member

alexcrichton commented Sep 7, 2017

@bors: r+

Thanks for the investigation!

We may want to investigate a platform-independent representation of Duration and Instant in the future, yeah, but that's fine to happen in a separate PR.

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 7, 2017

Contributor

📌 Commit 83d14bd has been approved by alexcrichton

Contributor

bors commented Sep 7, 2017

📌 Commit 83d14bd has been approved by alexcrichton

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 7, 2017

Member

@alexcrichton Filed issue #44394 for platform-indepndent representation of SystemTime. (Duration is already platform-independent. Instant have some tricky interaction on Windows which may be difficult to port.)

Member

kennytm commented Sep 7, 2017

@alexcrichton Filed issue #44394 for platform-indepndent representation of SystemTime. (Duration is already platform-independent. Instant have some tricky interaction on Windows which may be difficult to port.)

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Sep 7, 2017

Member

Thanks!

Member

alexcrichton commented Sep 7, 2017

Thanks!

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 9, 2017

Contributor

⌛️ Testing commit 83d14bd with merge 9999dc6...

Contributor

bors commented Sep 9, 2017

⌛️ Testing commit 83d14bd with merge 9999dc6...

bors added a commit that referenced this pull request Sep 9, 2017

Auto merge of #44220 - kennytm:fix-44216-instance-plus-max-duration-s…
…hould-panic, r=alexcrichton

Properly detect overflow in Instance ± Duration.

Fix #44216.
Fix #42622

The computation `Instant::now() + Duration::from_secs(u64::max_value())` now panics. The call `receiver.recv_timeout(Duration::from_secs(u64::max_value()))`, which involves such time addition, will also panic.

The reason #44216 arises is because of an unchecked cast from `u64` to `i64`, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an `i64`, yet this is rejected because (2⁶³) overflows the `i64`.
@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 9, 2017

Contributor

💔 Test failed - status-travis

Contributor

bors commented Sep 9, 2017

💔 Test failed - status-travis

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 9, 2017

Member

Legit. On macOS an Instant is represented by 64-bit nanoseconds, so u64::MAX seconds will overflow and converting to an Instant. The panic message is "overflow converting duration to nanoseconds", which is different from Windows' "overflow when converting duration to intervals". Fixed by just checking for the word "overflow" in the error pattern.

Member

kennytm commented Sep 9, 2017

Legit. On macOS an Instant is represented by 64-bit nanoseconds, so u64::MAX seconds will overflow and converting to an Instant. The panic message is "overflow converting duration to nanoseconds", which is different from Windows' "overflow when converting duration to intervals". Fixed by just checking for the word "overflow" in the error pattern.

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton
Member

alexcrichton commented Sep 9, 2017

@bors: r+

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 9, 2017

Contributor

📌 Commit c5e9ef6 has been approved by alexcrichton

Contributor

bors commented Sep 9, 2017

📌 Commit c5e9ef6 has been approved by alexcrichton

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 10, 2017

Contributor

⌛️ Testing commit c5e9ef6 with merge 49097d1...

Contributor

bors commented Sep 10, 2017

⌛️ Testing commit c5e9ef6 with merge 49097d1...

bors added a commit that referenced this pull request Sep 10, 2017

Auto merge of #44220 - kennytm:fix-44216-instance-plus-max-duration-s…
…hould-panic, r=alexcrichton

Properly detect overflow in Instance ± Duration.

Fix #44216.
Fix #42622

The computation `Instant::now() + Duration::from_secs(u64::max_value())` now panics. The call `receiver.recv_timeout(Duration::from_secs(u64::max_value()))`, which involves such time addition, will also panic.

The reason #44216 arises is because of an unchecked cast from `u64` to `i64`, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an `i64`, yet this is rejected because (2⁶³) overflows the `i64`.
@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 10, 2017

Contributor

💔 Test failed - status-travis

Contributor

bors commented Sep 10, 2017

💔 Test failed - status-travis

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 10, 2017

Member

@alexcrichton Fixed build failure. Sorry the import statement was wrong 😓.

Member

kennytm commented Sep 10, 2017

@alexcrichton Fixed build failure. Sorry the import statement was wrong 😓.

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton
Member

alexcrichton commented Sep 10, 2017

@bors: r+

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 10, 2017

Contributor

📌 Commit 4962f9d has been approved by alexcrichton

Contributor

bors commented Sep 10, 2017

📌 Commit 4962f9d has been approved by alexcrichton

@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 10, 2017

Contributor

⌛️ Testing commit 4962f9d with merge ca94c75...

Contributor

bors commented Sep 10, 2017

⌛️ Testing commit 4962f9d with merge ca94c75...

bors added a commit that referenced this pull request Sep 10, 2017

Auto merge of #44220 - kennytm:fix-44216-instance-plus-max-duration-s…
…hould-panic, r=alexcrichton

Properly detect overflow in Instance ± Duration.

Fix #44216.
Fix #42622

The computation `Instant::now() + Duration::from_secs(u64::max_value())` now panics. The call `receiver.recv_timeout(Duration::from_secs(u64::max_value()))`, which involves such time addition, will also panic.

The reason #44216 arises is because of an unchecked cast from `u64` to `i64`, making the duration equivalent to -1 second.

Note that the current implementation is over-conservative, since e.g. (-2⁶²) + (2⁶³) is perfectly fine for an `i64`, yet this is rejected because (2⁶³) overflows the `i64`.
@bors

This comment has been minimized.

Show comment
Hide comment
@bors

bors Sep 10, 2017

Contributor

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing ca94c75 to master...

Contributor

bors commented Sep 10, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing ca94c75 to master...

@bors bors merged commit 4962f9d into rust-lang:master Sep 10, 2017

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details

@kennytm kennytm deleted the kennytm:fix-44216-instance-plus-max-duration-should-panic branch Sep 11, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment