Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions crates/stdlib/src/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub(crate) use decl::module_def;
use crate::vm::{
PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, builtins::PyListRef,
};
use rustpython_host_env::select::{self as host_select, FdSet, RawFd};
use rustpython_host_env::select::{self as host_select, FdSet, RawFd, platform::FD_SETSIZE};
use std::io;

#[derive(Traverse)]
Expand Down Expand Up @@ -81,8 +81,22 @@ mod decl {

let seq2set = |list: &PyObject| -> PyResult<(Vec<Selectable>, FdSet)> {
let v: Vec<Selectable> = list.try_to_value(vm)?;

let too_many_fds = cfg_select! {
windows => v.len() > FD_SETSIZE as usize,
_ => v.len() > FD_SETSIZE,
};
if too_many_fds {
return Err(vm.new_value_error("too many file descriptors in select()"));
}
Comment thread
im-0 marked this conversation as resolved.

let mut fds = FdSet::new();
for fd in &v {
#[cfg(unix)]
if fd.fno as usize >= FD_SETSIZE {
return Err(vm.new_value_error("file descriptor out of range in select()"));
}

fds.insert(fd.fno);
}
Ok((v, fds))
Expand All @@ -97,11 +111,15 @@ mod decl {
return Ok((empty.clone(), empty.clone(), empty));
}

let nfds: i32 = [&mut r, &mut w, &mut x]
.iter_mut()
.filter_map(|set| set.highest())
.max()
.map_or(0, |n| n + 1) as _;
let nfds = cfg_select! {
windows => 0, // value is ignored on windows

_ => [&mut r, &mut w, &mut x]
.iter_mut()
.filter_map(|set| set.highest())
.max()
.map_or(0, |n| n + 1) as _,
};

loop {
let mut tv = timeout.map(host_select::sec_to_timeval);
Expand Down
25 changes: 25 additions & 0 deletions extra_tests/snippets/stdlib_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from testutils import assert_raises

TOO_MANY_SELECT_FDS = 4096


class Nope:
pass
Expand Down Expand Up @@ -42,3 +44,26 @@ def fileno(self):
assert recvr in rres

assert sendr in wres

# Too many descriptors for select.select()
if sys.platform != "win32":
import resource

soft_max_fds, hard_max_fds = resource.getrlimit(resource.RLIMIT_NOFILE)
if soft_max_fds != resource.RLIM_INFINITY:
# 100 additional fds should be enough for interpreter needs
need_fds = TOO_MANY_SELECT_FDS + 100

soft_max_fds = max(soft_max_fds, need_fds)
if hard_max_fds != resource.RLIM_INFINITY:
assert hard_max_fds >= soft_max_fds, (
"Not enough file descriptors for this test"
)
resource.setrlimit(resource.RLIMIT_NOFILE, (soft_max_fds, hard_max_fds))
sockets = [s for _ in range(TOO_MANY_SELECT_FDS // 2) for s in socket.socketpair()]
assert_raises(ValueError, select.select, sockets, [], [], 0)
del sockets
a, b = socket.socketpair()
# CPython disallows this on *nix systems too.
assert_raises(ValueError, select.select, [a] * TOO_MANY_SELECT_FDS, [], [], 0)
del a, b
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading