From 1909aebec577b21d98747477b88eb8cd6946e62a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 22 Jun 2025 00:19:45 +0900 Subject: [PATCH 1/4] Fix PosixSpawnArgs --- Lib/test/test_posix.py | 12 -------- vm/src/stdlib/posix.rs | 62 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 7e9e261d78..6388dececa 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1765,8 +1765,6 @@ def test_empty_file_actions(self): ) support.wait_process(pid, exitcode=0) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument resetids - @unittest.expectedFailure def test_resetids_explicit_default(self): pid = self.spawn_func( sys.executable, @@ -1776,8 +1774,6 @@ def test_resetids_explicit_default(self): ) support.wait_process(pid, exitcode=0) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument resetids - @unittest.expectedFailure def test_resetids(self): pid = self.spawn_func( sys.executable, @@ -1787,8 +1783,6 @@ def test_resetids(self): ) support.wait_process(pid, exitcode=0) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument setpgroup - @unittest.expectedFailure def test_setpgroup(self): pid = self.spawn_func( sys.executable, @@ -1819,8 +1813,6 @@ def test_setsigmask(self): ) support.wait_process(pid, exitcode=0) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument setsigmask - @unittest.expectedFailure def test_setsigmask_wrong_type(self): with self.assertRaises(TypeError): self.spawn_func(sys.executable, @@ -1836,8 +1828,6 @@ def test_setsigmask_wrong_type(self): os.environ, setsigmask=[signal.NSIG, signal.NSIG+1]) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument setsid - @unittest.expectedFailure def test_setsid(self): rfd, wfd = os.pipe() self.addCleanup(os.close, rfd) @@ -1902,7 +1892,6 @@ def test_setsigdef_wrong_type(self): [sys.executable, "-c", "pass"], os.environ, setsigdef=[signal.NSIG, signal.NSIG+1]) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument scheduler @unittest.expectedFailure @requires_sched @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')), @@ -1924,7 +1913,6 @@ def test_setscheduler_only_param(self): ) support.wait_process(pid, exitcode=0) - # TODO: RUSTPYTHON: TypeError: Unexpected keyword argument scheduler @unittest.expectedFailure @requires_sched @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')), diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index 0808c79b4c..9f235d8550 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -1361,6 +1361,16 @@ pub mod module { file_actions: Option>, #[pyarg(named, default)] setsigdef: Option>, + #[pyarg(named, default)] + setpgroup: Option, + #[pyarg(named, default)] + resetids: bool, + #[pyarg(named, default)] + setsid: bool, + #[pyarg(named, default)] + setsigmask: Option>, + #[pyarg(named, default)] + scheduler: Option, } #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))] @@ -1459,6 +1469,58 @@ pub mod module { ); } + // Handle new posix_spawn attributes + let mut flags = 0i32; + + if let Some(pgid) = self.setpgroup { + assert!(unsafe { libc::posix_spawnattr_setpgroup(&mut attrp, pgid) } == 0); + flags |= libc::POSIX_SPAWN_SETPGROUP; + } + + if self.resetids { + flags |= libc::POSIX_SPAWN_RESETIDS; + } + + if self.setsid { + // Note: POSIX_SPAWN_SETSID may not be available on all platforms + #[cfg(any(target_os = "linux"))] + { + flags |= 0x0080; // POSIX_SPAWN_SETSID value on Linux + } + #[cfg(not(target_os = "linux"))] + { + return Err(vm.new_not_implemented_error( + "setsid parameter is not supported on this platform".to_owned(), + )); + } + } + + if let Some(sigs) = self.setsigmask { + use nix::sys::signal; + let mut set = signal::SigSet::empty(); + for sig in sigs.iter(vm)? { + let sig = sig?; + let sig = signal::Signal::try_from(sig).map_err(|_| { + vm.new_value_error(format!("signal number {sig} out of range")) + })?; + set.add(sig); + } + assert!(unsafe { libc::posix_spawnattr_setsigmask(&mut attrp, set.as_ref()) } == 0); + flags |= libc::POSIX_SPAWN_SETSIGMASK; + } + + if let Some(_scheduler) = self.scheduler { + // TODO: Implement scheduler parameter handling + // This requires platform-specific sched_param struct handling + return Err(vm.new_not_implemented_error( + "scheduler parameter is not yet implemented".to_owned(), + )); + } + + if flags != 0 { + assert!(unsafe { libc::posix_spawnattr_setflags(&mut attrp, flags as i16) } == 0); + } + let mut args: Vec = self .args .iter(vm)? From 40789929a738a48c92ab4dfe4f2c54260d213a17 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 22 Jun 2025 00:21:52 +0900 Subject: [PATCH 2/4] test_specify_environment --- Lib/test/test_posix.py | 2 -- vm/src/stdlib/posix.rs | 37 +++++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 6388dececa..30d6b6d3c3 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1730,8 +1730,6 @@ def test_no_such_executable(self): self.assertEqual(pid2, pid) self.assertNotEqual(status, 0) - # TODO: RUSTPYTHON: TypeError: '_Environ' object is not a mapping - @unittest.expectedFailure def test_specify_environment(self): envfile = os_helper.TESTFN self.addCleanup(os_helper.unlink, envfile) diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index 9f235d8550..054871eefc 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -1308,20 +1308,33 @@ pub mod module { env: crate::function::ArgMapping, vm: &VirtualMachine, ) -> PyResult> { - let keys = env.mapping().keys(vm)?; - let values = env.mapping().values(vm)?; + let items = env.mapping().items(vm)?; - let keys = PyListRef::try_from_object(vm, keys) - .map_err(|_| vm.new_type_error("env.keys() is not a list".to_owned()))? - .borrow_vec() - .to_vec(); - let values = PyListRef::try_from_object(vm, values) - .map_err(|_| vm.new_type_error("env.values() is not a list".to_owned()))? - .borrow_vec() - .to_vec(); + // Convert items to list if it isn't already + let items = vm.ctx.new_list( + items + .get_iter(vm)? + .iter(vm)? + .collect::>>()?, + ); - keys.into_iter() - .zip(values) + items + .borrow_vec() + .iter() + .map(|item| { + let tuple = item + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("items() should return tuples".to_owned()))?; + let tuple_items = tuple.as_slice(); + if tuple_items.len() != 2 { + return Err(vm.new_value_error( + "items() tuples should have exactly 2 elements".to_owned(), + )); + } + Ok((tuple_items[0].clone(), tuple_items[1].clone())) + }) + .collect::>>()? + .into_iter() .map(|(k, v)| { let k = OsPath::try_from_object(vm, k)?.into_bytes(); let v = OsPath::try_from_object(vm, v)?.into_bytes(); From dde43023980f8f079eb8fddc0aedebe1559b82b4 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 22 Jun 2025 00:35:04 +0900 Subject: [PATCH 3/4] fixupo --- vm/src/stdlib/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index 054871eefc..86c3910f74 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -1496,7 +1496,7 @@ pub mod module { if self.setsid { // Note: POSIX_SPAWN_SETSID may not be available on all platforms - #[cfg(any(target_os = "linux"))] + #[cfg(target_os = "linux")] { flags |= 0x0080; // POSIX_SPAWN_SETSID value on Linux } From 151598c19a2b18b73ed27a3e9b397dd2f1ab0ca4 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 22 Jun 2025 09:25:41 +0900 Subject: [PATCH 4/4] Apply reviews --- vm/src/stdlib/posix.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index 86c3910f74..8eecaaf119 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -1486,7 +1486,10 @@ pub mod module { let mut flags = 0i32; if let Some(pgid) = self.setpgroup { - assert!(unsafe { libc::posix_spawnattr_setpgroup(&mut attrp, pgid) } == 0); + let ret = unsafe { libc::posix_spawnattr_setpgroup(&mut attrp, pgid) }; + if ret != 0 { + return Err(vm.new_os_error(format!("posix_spawnattr_setpgroup failed: {ret}"))); + } flags |= libc::POSIX_SPAWN_SETPGROUP; } @@ -1518,7 +1521,12 @@ pub mod module { })?; set.add(sig); } - assert!(unsafe { libc::posix_spawnattr_setsigmask(&mut attrp, set.as_ref()) } == 0); + let ret = unsafe { libc::posix_spawnattr_setsigmask(&mut attrp, set.as_ref()) }; + if ret != 0 { + return Err( + vm.new_os_error(format!("posix_spawnattr_setsigmask failed: {ret}")) + ); + } flags |= libc::POSIX_SPAWN_SETSIGMASK; } @@ -1531,7 +1539,15 @@ pub mod module { } if flags != 0 { - assert!(unsafe { libc::posix_spawnattr_setflags(&mut attrp, flags as i16) } == 0); + // Check for potential overflow when casting to c_short + if flags > libc::c_short::MAX as i32 { + return Err(vm.new_value_error("Too many flags set for posix_spawn".to_owned())); + } + let ret = + unsafe { libc::posix_spawnattr_setflags(&mut attrp, flags as libc::c_short) }; + if ret != 0 { + return Err(vm.new_os_error(format!("posix_spawnattr_setflags failed: {ret}"))); + } } let mut args: Vec = self