Skip to content

Commit 783cca6

Browse files
committed
Validate timeout in ThreadHandle::join to prevent panic
1 parent 47cf683 commit 783cca6

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

crates/vm/src/function/number.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,13 @@ impl TimeoutSeconds {
219219

220220
impl TryFromObject for TimeoutSeconds {
221221
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
222-
super::Either::<f64, i64>::try_from_object(vm, obj).map(|e| match e {
223-
super::Either::A(f) => Self { value: f },
224-
super::Either::B(i) => Self { value: i as f64 },
225-
})
222+
let value = match super::Either::<f64, i64>::try_from_object(vm, obj)? {
223+
super::Either::A(f) => f,
224+
super::Either::B(i) => i as f64,
225+
};
226+
if value.is_nan() {
227+
return Err(vm.new_value_error("Invalid value NaN (not a number)".to_owned()));
228+
}
229+
Ok(Self { value })
226230
}
227231
}

crates/vm/src/stdlib/thread.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,12 @@ pub(crate) mod _thread {
7979
Ok(true)
8080
}
8181
true if timeout < 0.0 => {
82-
Err(vm.new_value_error("timeout value must be positive".to_owned()))
82+
Err(vm.new_value_error("timeout value must be a non-negative number".to_owned()))
8383
}
8484
true => {
85-
// modified from std::time::Duration::from_secs_f64 to avoid a panic.
86-
// TODO: put this in the Duration::try_from_object impl, maybe?
87-
let nanos = timeout * 1_000_000_000.0;
88-
if timeout > TIMEOUT_MAX as f64 || nanos < 0.0 || !nanos.is_finite() {
85+
if timeout > TIMEOUT_MAX {
8986
return Err(vm.new_overflow_error(
90-
"timestamp too large to convert to Rust Duration".to_owned(),
87+
"timeout value is too large".to_owned(),
9188
));
9289
}
9390

@@ -1096,7 +1093,16 @@ pub(crate) mod _thread {
10961093
let timeout_duration = match timeout.flatten() {
10971094
Some(t) => {
10981095
let secs = t.to_secs_f64();
1099-
(secs >= 0.0).then(|| Duration::from_secs_f64(secs))
1096+
if secs >= 0.0 {
1097+
if secs > TIMEOUT_MAX {
1098+
return Err(vm.new_overflow_error(
1099+
"timeout value is too large".to_owned(),
1100+
));
1101+
}
1102+
Some(Duration::from_secs_f64(secs))
1103+
} else {
1104+
None
1105+
}
11001106
}
11011107
_ => None,
11021108
};

0 commit comments

Comments
 (0)