mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Fix panic in select.select() when too many FDs specified (#7948)
Also:
* Add regression test into existing `extra_tests/snippets/stdlib_select.py`
* Stop calculating nfds on Windows as it is ignored there
Panic:
thread 'main' (189598) panicked at /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.186/src/unix/linux_like/mod.rs:1777:9:
index out of bounds: the len is 16 but the index is 16
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' (189598) panicked at library/core/src/panicking.rs:225:5:
panic in a function that cannot unwind
stack backtrace:
0: 0xaaab763a0b88 - <<std[1934960bf7f41d0a]::sys::backtrace::BacktraceLock>::print::DisplayBacktrace as core[f1abae5f1257fe69]::fmt::Display>::fmt
1: 0xaaab75590ff0 - core[f1abae5f1257fe69]::fmt::write
2: 0xaaab763a94fc - <std[1934960bf7f41d0a]::sys::stdio::unix::Stderr as std[1934960bf7f41d0a]::io::Write>::write_fmt
3: 0xaaab7638b714 - std[1934960bf7f41d0a]::panicking::default_hook::{closure#0}
4: 0xaaab7639b288 - std[1934960bf7f41d0a]::panicking::default_hook
5: 0xaaab7639b478 - std[1934960bf7f41d0a]::panicking::panic_with_hook
6: 0xaaab7638b7ec - std[1934960bf7f41d0a]::panicking::panic_handler::{closure#0}
7: 0xaaab76382654 - std[1934960bf7f41d0a]::sys::backtrace::__rust_end_short_backtrace::<std[1934960bf7f41d0a]::panicking::panic_handler::{closure#0}, !>
8: 0xaaab7638c504 - __rustc[b7425922bef61dcf]::rust_begin_unwind
9: 0xaaab754f778c - core[f1abae5f1257fe69]::panicking::panic_nounwind_fmt
10: 0xaaab754f7714 - core[f1abae5f1257fe69]::panicking::panic_nounwind
11: 0xaaab754f786c - core[f1abae5f1257fe69]::panicking::panic_cannot_unwind
12: 0xaaab75a6283c - rustpython_vm::function::builtin::<impl rustpython_vm::function::builtin::sealed::PyNativeFnInternal<(rustpython_vm::function::builtin::OwnedParam<T1>,rustpython_vm::function::builtin::OwnedParam<T2>,rustpython_vm::function::builtin::OwnedParam<T3>,rustpython_vm::function::builtin::OwnedParam<T4>),R,rustpython_vm::vm::VirtualMachine> for F>::call_::h2471c8e242c9b51d
13: 0xaaab75db1e68 - rustpython_vm::types::slot::Callable::slot_call::hd1c1ad0ad14f306b
14: 0xaaab762c0a50 - rustpython_vm::protocol::callable::PyCallable::invoke::h9f6d571fca351ca6
15: 0xaaab75c550e8 - rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::call_with_args::hed1f4a61aba2dced
16: 0xaaab762e7c24 - rustpython_vm::frame::ExecutingFrame::execute_call::h0ad3490dd74ed1e3
17: 0xaaab762fed40 - rustpython_vm::frame::ExecutingFrame::run::hcf90f0950fc26812
18: 0xaaab761e6768 - rustpython_vm::vm::VirtualMachine::with_frame::hd49ba6fcdf2422e2
19: 0xaaab75c45398 - rustpython_vm::builtins::function::<impl rustpython_vm::object::core::Py<rustpython_vm::builtins::function::PyFunction>>::invoke_with_locals::h42de3d2316941ce2
20: 0xaaab76132a80 - rustpython_vm::builtins::function::vectorcall_function::h7331cb67b334e867
21: 0xaaab763369d8 - rustpython_vm::protocol::callable::<impl rustpython_vm::object::core::PyObject>::vectorcall::h9019c5d16685c89a
22: 0xaaab762f4b54 - rustpython_vm::frame::ExecutingFrame::execute_call_vectorcall::h120134e11a58c946
23: 0xaaab76302a7c - rustpython_vm::frame::ExecutingFrame::run::hcf90f0950fc26812
24: 0xaaab761e6768 - rustpython_vm::vm::VirtualMachine::with_frame::hd49ba6fcdf2422e2
25: 0xaaab761e7f24 - rustpython_vm::vm::VirtualMachine::run_code_obj::h354618be6e5cc553
26: 0xaaab761e2d18 - rustpython_vm::vm::python_run::file_run::<impl rustpython_vm::vm::VirtualMachine>::run_any_file::h783d3127fbc0b523
27: 0xaaab757d700c - rustpython::run_rustpython::h354efb8d817cefbf
28: 0xaaab757c79e0 - std::thread::local::LocalKey<T>::with::hc9728e249843a926
29: 0xaaab757db860 - rustpython_vm::vm::interpreter::Interpreter::run::h42ac1fe9ed2287a2
30: 0xaaab757d7b30 - rustpython::run::hf14a209db5b4289c
31: 0xaaab757e2eb4 - rustpython::main::h1b59d8e13276ac48
32: 0xaaab757e2eec - std::sys::backtrace::__rust_begin_short_backtrace::h47e4b1f073f2155c
33: 0xaaab757e2ed4 - std::rt::lang_start::{{closure}}::h663a6c3dc7d80101
34: 0xaaab76399fd4 - std[1934960bf7f41d0a]::rt::lang_start_internal
35: 0xaaab757e2f44 - main
36: 0xfffed057655c - __libc_start_call_main
37: 0xfffed057663c - __libc_start_main@@GLIBC_2.34
38: 0xaaab755526f0 - _start
39: 0x0 - <unknown>
thread caused non-unwinding panic. aborting.
Aborted (core dumped) cargo run --release -- extra_tests/snippets/stdlib_select.py
This commit is contained in:
@@ -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)]
|
||||
@@ -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()"));
|
||||
}
|
||||
|
||||
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))
|
||||
@@ -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);
|
||||
|
||||
@@ -4,6 +4,8 @@ import sys
|
||||
|
||||
from testutils import assert_raises
|
||||
|
||||
TOO_MANY_SELECT_FDS = 4096
|
||||
|
||||
|
||||
class Nope:
|
||||
pass
|
||||
@@ -42,3 +44,26 @@ if "win" not in sys.platform:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user