From 8376a03366d8309345c2fd898a097283c57a062b Mon Sep 17 00:00:00 2001 From: Jeaeun Kim <109906379+kyokuping@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:16:42 +0900 Subject: [PATCH] Match CPython unsigned socket conversion errors (#8257) Assisted-by: Codex:gpt-5.4 --- Lib/test/test_lzma.py | 1 - Lib/test/test_memoryio.py | 8 -------- Lib/test/test_resource.py | 1 - Lib/test/test_socket.py | 2 -- crates/stdlib/src/array.rs | 2 +- crates/stdlib/src/socket.rs | 8 +++++--- crates/vm/src/builtins/int.rs | 16 ++++++++++------ crates/vm/src/stdlib/os.rs | 3 ++- 8 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index eebe6370f..fff261d89 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -656,7 +656,6 @@ class FileTestCase(unittest.TestCase): with self.assertRaises(ValueError): LZMAFile(BytesIO(COMPRESSED_XZ), check=lzma.CHECK_UNKNOWN) - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u32 def test_init_bad_preset(self): with self.assertRaises(TypeError): LZMAFile(BytesIO(), "w", preset=4.39) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index 0ae486005..f0c21e4ae 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -934,10 +934,6 @@ class CBytesIOTest(PyBytesIOTest): def test_write(self): return super().test_write() - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u64 - def test_seek(self): - return super().test_seek() - class CStringIOTest(PyStringIOTest): ioclass = io.StringIO UnsupportedOperation = io.UnsupportedOperation @@ -1030,10 +1026,6 @@ class CStringIOTest(PyStringIOTest): def test_newlines_property(self): return super().test_newlines_property() - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u64 - def test_seek(self): - return super().test_seek() - @unittest.expectedFailure # TODO: RUSTPYTHON; d def test_newline_cr(self): return super().test_newline_cr() diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py index e2226e1a6..6c7145caa 100644 --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -151,7 +151,6 @@ class ResourceTest(unittest.TestCase): resource.setrlimit(resource.RLIMIT_FSIZE, (2**64-5, max)) self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**64-5)) - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u64 @unittest.skipIf(sys.platform == "vxworks", "setting RLIMIT_FSIZE is not supported on VxWorks") @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE') diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index ccc06ceba..ddeb868db 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1181,7 +1181,6 @@ class GeneralModuleTests(unittest.TestCase): self.assertIsInstance(_name, str) self.assertEqual(name, _name) - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u32 @unittest.skipUnless(hasattr(socket, 'if_indextoname'), 'socket.if_indextoname() not available.') @support.skip_android_selinux('if_indextoname') @@ -1249,7 +1248,6 @@ class GeneralModuleTests(unittest.TestCase): self.assertEqual(swapped & mask, mask) self.assertRaises(OverflowError, func, 1<<34) - @unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u16 def testNtoHErrors(self): s_good_values = [0, 1, 2, 0xffff] l_good_values = s_good_values + [0xffffffff] diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index e9b389949..19f6c48f2 100644 --- a/crates/stdlib/src/array.rs +++ b/crates/stdlib/src/array.rs @@ -498,7 +498,7 @@ pub mod array { ($($t:ty,)*) => {$( impl ArrayElement for $t { fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - obj.try_index(vm)?.try_to_primitive(vm) + obj.try_index(vm)?.try_to_primitive_raw(vm) } fn byteswap(self) -> Self { <$t>::swap_bytes(self) diff --git a/crates/stdlib/src/socket.rs b/crates/stdlib/src/socket.rs index e7ee6c907..9cb197ab9 100644 --- a/crates/stdlib/src/socket.rs +++ b/crates/stdlib/src/socket.rs @@ -2230,7 +2230,7 @@ mod _socket { let addr = Self::from_tuple(tuple, vm)?; let flowinfo = tuple .get(2) - .map(|obj| u32::try_from_borrowed_object(vm, obj)) + .map(|obj| obj.clone().try_index(vm)?.try_to_primitive_raw(vm)) .transpose()? .unwrap_or(0); let scopeid = tuple @@ -3141,14 +3141,16 @@ mod _socket { #[cfg(all(unix, not(target_os = "redox")))] #[pyfunction(name = "CMSG_LEN")] - fn cmsg_len(length: usize, vm: &VirtualMachine) -> PyResult { + fn cmsg_len(length: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let length = length.try_index(vm)?.try_to_primitive_raw(vm)?; host_socket::checked_cmsg_len(length) .ok_or_else(|| vm.new_overflow_error("CMSG_LEN() argument out of range")) } #[cfg(all(unix, not(target_os = "redox")))] #[pyfunction(name = "CMSG_SPACE")] - fn cmsg_space(length: usize, vm: &VirtualMachine) -> PyResult { + fn cmsg_space(length: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let length = length.try_index(vm)?.try_to_primitive_raw(vm)?; host_socket::checked_cmsg_space(length) .ok_or_else(|| vm.new_overflow_error("CMSG_SPACE() argument out of range")) } diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index c5aa607d0..278a9cecb 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -343,13 +343,17 @@ impl PyInt { where I: PrimInt + TryFrom<&'a BigInt>, { - // TODO: Python 3.14+: ValueError for negative int to unsigned type - // See stdlib_socket.py socket.htonl(-1) - // - // if I::min_value() == I::zero() && self.as_bigint().sign() == Sign::Minus { - // return Err(vm.new_value_error("Cannot convert negative int".to_owned())); - // } + if I::min_value() == I::zero() && self.as_bigint().sign() == Sign::Minus { + return Err(vm.new_value_error("can't convert negative number to unsigned")); + } + self.try_to_primitive_raw(vm) + } + + pub fn try_to_primitive_raw<'a, I>(&'a self, vm: &VirtualMachine) -> PyResult + where + I: PrimInt + TryFrom<&'a BigInt>, + { I::try_from(self.as_bigint()).map_err(|_| { vm.new_overflow_error(format!( "Python int too large to convert to Rust {}", diff --git a/crates/vm/src/stdlib/os.rs b/crates/vm/src/stdlib/os.rs index e6aea44c3..5772cc46f 100644 --- a/crates/vm/src/stdlib/os.rs +++ b/crates/vm/src/stdlib/os.rs @@ -1870,7 +1870,8 @@ pub(super) mod _os { #[cfg(windows)] #[pyfunction] - fn waitstatus_to_exitcode(status: u64, vm: &VirtualMachine) -> PyResult { + fn waitstatus_to_exitcode(status: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let status = status.try_index(vm)?.try_to_primitive_raw::(vm)?; let exitcode = status >> 8; // ExitProcess() accepts an UINT type: // reject exit code which doesn't fit in an UINT