-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Fix overflow error in thread::sleep #34363
Conversation
r? @brson (rust_highfive has picked a reviewer for you, use r? to override) |
Rather than a test we should just iteratate and call sleep multiple times with duration of up-to the allowed amount. |
@@ -125,8 +126,10 @@ impl Thread { | |||
} | |||
|
|||
pub fn sleep(dur: Duration) { | |||
let secs = dur.as_secs(); | |||
assert!(secs <= (u64::MAX >> 1), "secs number is too big"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error happens because “The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million.” u64::MAX >> 1
is not 1000 million and that’s seconds too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait, my bad. Disregard me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it still would be more clear if you did something like:
let secs = dur.as_secs() as libc::time_t;
assert!(secs.is_positive(), "...");
Your current approach won’t catch the cases where time_t
is i32
(some versions of windows, mips linux etc)
Also needs a regression test. You should either mock-out the nanosleep function or invoke a new thread/process and catch a signal of some sort sent to it by the parent. |
fn get_secs(secs: &mut u64) -> libc::time_t { | ||
if *secs >= libc::time_t::max_value() as u64 { | ||
*secs -= libc::time_t::max_value() as u64 - 1; | ||
libc::time_t::max_value() - 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why - 1
here and above this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It fails if >= 1000000. So I put the max minus one.
r=me with |
@@ -125,16 +125,32 @@ impl Thread { | |||
} | |||
|
|||
pub fn sleep(dur: Duration) { | |||
fn get_secs(secs: &mut u64) -> libc::time_t { | |||
if *secs > libc::time_t::max_value() as u64 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this could be:
let amt = cmp::min(libc::time_t::max_value() as u64, *secs);
*secs -= amt;
amt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a right thing to do.
assert_eq!(os::errno(), libc::EINTR); | ||
} | ||
secs += ts.tv_sec as u64; | ||
nsecs = ts.tv_nsec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly, documentation for nanosleep does not specify what ts
contains after a successful call, therefore, in order to be on the safe side, you want to only do this in case the nanosleep call fails and set these fields to 0 otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea!
@bors r=nagisa f053216 |
⌛ Testing commit f053216 with merge ac9ba4e... |
@bors: r- Ah there's still a loop that's needed, I'll comment to it. |
@bors: r+ oh nvmd I see, just had to think for a second... |
📌 Commit f053216 has been approved by |
💔 Test failed - auto-linux-64-x-android-t |
Ah, |
What about |
Or... spawn a thread which sleeps for a smaller amount of time and then exits? |
@alexcrichton: I take your solution! :) |
Updated. |
|
||
#![feature(libc)] | ||
|
||
extern crate libc; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this and feature
and // ignore
above can all be removed
Updated. |
@bors: r+ ae544c5b156a56b1a170ea669487fde0c417545a |
I put back the feature. |
Actually |
Fix overflow error in thread::sleep Fixes rust-lang#34330 I added a test to have a more clear error inside the function. Since `time_t` is `i64` and we expect `u64`, maybe we should changed the awaited type?
Fix overflow error in thread::sleep Fixes rust-lang#34330 I added a test to have a more clear error inside the function. Since `time_t` is `i64` and we expect `u64`, maybe we should changed the awaited type?
Fixes #34330
I added a test to have a more clear error inside the function. Since
time_t
isi64
and we expectu64
, maybe we should changed the awaited type?