Skip to content

Commit 435159e

Browse files
[5895] added code to raise error in sleep if invalid value
1 parent 9336507 commit 435159e

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

Lib/test/test_time.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,17 @@ def test_conversions(self):
155155
def test_sleep(self):
156156
self.assertRaises(ValueError, time.sleep, -2)
157157
self.assertRaises(ValueError, time.sleep, -1)
158+
self.assertRaises(ValueError, time.sleep, float('nan'))
159+
self.assertRaises(ValueError, time.sleep, float('inf'))
160+
self.assertRaises(ValueError, time.sleep, -float('inf'))
161+
self.assertRaises(ValueError, time.sleep, 1e100)
162+
time.sleep(0)
163+
time.sleep(0.000001)
164+
time.sleep(1e-9)
165+
time.sleep(0.5)
158166
time.sleep(1.2)
167+
time.sleep(2)
168+
159169

160170
# TODO: RUSTPYTHON
161171
@unittest.expectedFailure

vm/src/stdlib/time.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,22 @@ mod decl {
9090

9191
#[cfg(not(unix))]
9292
#[pyfunction]
93-
fn sleep(dur: Duration) {
94-
std::thread::sleep(dur);
93+
fn sleep(secs: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
94+
// Try to get as float first, if that fails try as integer
95+
let secs = if let Ok(float_val) = f64::try_from_object(vm, secs.clone()) {
96+
float_val
97+
} else if let Ok(int_val) = i64::try_from_object(vm, secs) {
98+
int_val as f64
99+
} else {
100+
return Err(vm.new_type_error("sleep() argument must be a number"));
101+
};
102+
if !secs.is_finite() || secs < 0.0 || secs > u64::MAX as f64 {
103+
return Err(vm.new_value_error("sleep length must be a non-negative finite number"));
104+
}
105+
106+
let duration = Duration::from_secs_f64(secs);
107+
std::thread::sleep(duration);
108+
Ok(())
95109
}
96110

97111
#[cfg(not(target_os = "wasi"))]
@@ -527,7 +541,7 @@ mod platform {
527541
use crate::{
528542
PyObject, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine,
529543
builtins::{PyNamespace, PyStrRef},
530-
convert::IntoPyException,
544+
convert::{IntoPyException,TryFromObject},
531545
};
532546
use nix::{sys::time::TimeSpec, time::ClockId};
533547
use std::time::Duration;
@@ -691,9 +705,20 @@ mod platform {
691705
}
692706

693707
#[pyfunction]
694-
fn sleep(dur: Duration, vm: &VirtualMachine) -> PyResult<()> {
708+
fn sleep(secs: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
695709
// this is basically std::thread::sleep, but that catches interrupts and we don't want to;
696-
710+
// Try to get as float first, if that fails try as integer
711+
let secs = if let Ok(float_val) = f64::try_from_object(vm, secs.clone()) {
712+
float_val
713+
} else if let Ok(int_val) = i64::try_from_object(vm, secs) {
714+
int_val as f64
715+
} else {
716+
return Err(vm.new_type_error("sleep() argument must be a number"));
717+
};
718+
if !secs.is_finite() || secs < 0.0 || secs > u64::MAX as f64 {
719+
return Err(vm.new_value_error("sleep length must be a non-negative finite number"));
720+
}
721+
let dur = Duration::from_secs_f64(secs);
697722
let ts = TimeSpec::from(dur);
698723
let res = unsafe { libc::nanosleep(ts.as_ref(), std::ptr::null_mut()) };
699724
let interrupted = res == -1 && nix::Error::last_raw() == libc::EINTR;

0 commit comments

Comments
 (0)