From 05f982974668092b74bf74c20a8615c2cbdaa026 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 19 Apr 2025 02:56:06 +0900 Subject: [PATCH 1/2] test_poll3 --- Lib/test/test_poll.py | 2 -- stdlib/src/select.rs | 56 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index 338eb00f0c..a9bfb755c3 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -152,8 +152,6 @@ def test_poll2(self): else: self.fail('Unexpected return value from select.poll: %s' % fdlist) - # TODO: RUSTPYTHON int overflow - @unittest.expectedFailure def test_poll3(self): # test int overflow pollster = select.poll() diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index f600d60ede..6639541dd4 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -330,7 +330,7 @@ mod decl { use super::*; use crate::vm::{ AsObject, PyPayload, - builtins::PyFloat, + builtins::{PyFloat, PyIntRef}, common::lock::PyMutex, convert::{IntoPyException, ToPyObject}, function::OptionalArg, @@ -338,7 +338,10 @@ mod decl { }; use libc::pollfd; use num_traits::{Signed, ToPrimitive}; - use std::time::{Duration, Instant}; + use std::{ + convert::TryFrom, + time::{Duration, Instant}, + }; #[derive(Default)] pub(super) struct TimeoutArg(pub Option); @@ -422,20 +425,51 @@ mod decl { #[pyclass] impl PyPoll { #[pymethod] - fn register(&self, Fildes(fd): Fildes, eventmask: OptionalArg) { - insert_fd( - &mut self.fds.lock(), - fd, - eventmask.map_or(DEFAULT_EVENTS, |e| e as i16), - ) + fn register( + &self, + Fildes(fd): Fildes, + eventmask: OptionalArg, + vm: &VirtualMachine, + ) -> PyResult<()> { + let mask = match eventmask { + OptionalArg::Present(int_ref) => { + let val = int_ref.as_bigint(); + if val.is_negative() { + return Err(vm.new_value_error("negative event mask".to_owned())); + } + // Try converting to i16, should raise OverflowError if too large + i16::try_from(val).map_err(|_| { + vm.new_overflow_error("event mask value out of range".to_owned()) + })? + } + OptionalArg::Missing => DEFAULT_EVENTS, + }; + insert_fd(&mut self.fds.lock(), fd, mask); + Ok(()) } #[pymethod] - fn modify(&self, Fildes(fd): Fildes, eventmask: u16) -> io::Result<()> { + fn modify( + &self, + Fildes(fd): Fildes, + eventmask: PyIntRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + let mask = { + let val = eventmask.as_bigint(); + if val.is_negative() { + return Err(vm.new_value_error("negative event mask".to_owned())); + } + // Try converting to i16, should raise OverflowError if too large + i16::try_from(val).map_err(|_| { + vm.new_overflow_error("event mask value out of range".to_owned()) + })? + }; let mut fds = self.fds.lock(); + // CPython raises KeyError if fd is not registered, match that behavior let pfd = get_fd_mut(&mut fds, fd) - .ok_or_else(|| io::Error::from_raw_os_error(libc::ENOENT))?; - pfd.events = eventmask as i16; + .ok_or_else(|| vm.new_key_error(vm.ctx.new_int(fd).into()))?; + pfd.events = mask; Ok(()) } From ca17cb9d01f51c4f3a65149df51ed3abff1772e9 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 20 Apr 2025 18:29:24 +0900 Subject: [PATCH 2/2] Refactor EventMask --- stdlib/src/select.rs | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index 6639541dd4..1119f0cd9d 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -330,7 +330,7 @@ mod decl { use super::*; use crate::vm::{ AsObject, PyPayload, - builtins::{PyFloat, PyIntRef}, + builtins::PyFloat, common::lock::PyMutex, convert::{IntoPyException, ToPyObject}, function::OptionalArg, @@ -420,6 +420,32 @@ mod decl { search(fds, fd).ok().map(|i| fds.remove(i)) } + // new EventMask type + #[derive(Copy, Clone)] + #[repr(transparent)] + pub struct EventMask(pub i16); + + impl TryFromObject for EventMask { + fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + use crate::builtins::PyInt; + let int = obj + .downcast::() + .map_err(|_| vm.new_type_error("argument must be an integer".to_owned()))?; + + let val = int.as_bigint(); + if val.is_negative() { + return Err(vm.new_value_error("negative event mask".to_owned())); + } + + // Try converting to i16, should raise OverflowError if too large + let mask = i16::try_from(val).map_err(|_| { + vm.new_overflow_error("event mask value out of range".to_owned()) + })?; + + Ok(EventMask(mask)) + } + } + const DEFAULT_EVENTS: i16 = libc::POLLIN | libc::POLLPRI | libc::POLLOUT; #[pyclass] @@ -428,20 +454,10 @@ mod decl { fn register( &self, Fildes(fd): Fildes, - eventmask: OptionalArg, - vm: &VirtualMachine, + eventmask: OptionalArg, ) -> PyResult<()> { let mask = match eventmask { - OptionalArg::Present(int_ref) => { - let val = int_ref.as_bigint(); - if val.is_negative() { - return Err(vm.new_value_error("negative event mask".to_owned())); - } - // Try converting to i16, should raise OverflowError if too large - i16::try_from(val).map_err(|_| { - vm.new_overflow_error("event mask value out of range".to_owned()) - })? - } + OptionalArg::Present(event_mask) => event_mask.0, OptionalArg::Missing => DEFAULT_EVENTS, }; insert_fd(&mut self.fds.lock(), fd, mask); @@ -452,24 +468,14 @@ mod decl { fn modify( &self, Fildes(fd): Fildes, - eventmask: PyIntRef, + eventmask: EventMask, vm: &VirtualMachine, ) -> PyResult<()> { - let mask = { - let val = eventmask.as_bigint(); - if val.is_negative() { - return Err(vm.new_value_error("negative event mask".to_owned())); - } - // Try converting to i16, should raise OverflowError if too large - i16::try_from(val).map_err(|_| { - vm.new_overflow_error("event mask value out of range".to_owned()) - })? - }; let mut fds = self.fds.lock(); // CPython raises KeyError if fd is not registered, match that behavior let pfd = get_fd_mut(&mut fds, fd) .ok_or_else(|| vm.new_key_error(vm.ctx.new_int(fd).into()))?; - pfd.events = mask; + pfd.events = eventmask.0; Ok(()) }