From b9fa405fd4b9ef7e408b3a47c8301d9dda88e88c Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Fri, 12 Dec 2025 19:55:57 +0900 Subject: [PATCH 1/2] Fix test_subprocess --- Lib/test/test_subprocess.py | 1 - crates/vm/src/stdlib/winapi.rs | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 87562230261..bf0099554b5 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -857,7 +857,6 @@ def test_one_environment_variable(self): self.assertEqual(p.returncode, 0) self.assertEqual(stdout.strip(), b"fruit=orange") - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON, null byte is not checked") def test_invalid_cmd(self): # null character in the command name cmd = sys.executable + '\0' diff --git a/crates/vm/src/stdlib/winapi.rs b/crates/vm/src/stdlib/winapi.rs index 3fb1068a60e..1df3ff0e42d 100644 --- a/crates/vm/src/stdlib/winapi.rs +++ b/crates/vm/src/stdlib/winapi.rs @@ -248,6 +248,18 @@ mod _winapi { Ok(ws.into_vec_with_nul()) }; + // Validate no embedded null bytes in command name and command line + if let Some(ref name) = args.name + && name.as_str().contains('\0') + { + return Err(crate::exceptions::cstring_error(vm)); + } + if let Some(ref cmd) = args.command_line + && cmd.as_str().contains('\0') + { + return Err(crate::exceptions::cstring_error(vm)); + } + let app_name = args.name.map(wstr).transpose()?; let app_name = app_name.as_ref().map_or_else(null, |w| w.as_ptr()); From 752c0f68fd76b76aa85552be33a880fac65745e7 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Fri, 12 Dec 2025 20:12:30 +0900 Subject: [PATCH 2/2] fix windows locale --- Lib/test/test_locale.py | 1 - crates/stdlib/src/locale.rs | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py index 9e1f46f6444..71d03f3a3f9 100644 --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,6 @@ def test_getsetlocale_issue1813(self): self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}") self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; Error not raised') @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_setlocale_long_encoding(self): with self.assertRaises(locale.Error): diff --git a/crates/stdlib/src/locale.rs b/crates/stdlib/src/locale.rs index 630d2a419d4..6cca8b9123b 100644 --- a/crates/stdlib/src/locale.rs +++ b/crates/stdlib/src/locale.rs @@ -198,6 +198,34 @@ mod _locale { locale: OptionalArg>, } + /// Maximum code page encoding name length on Windows + #[cfg(windows)] + const MAX_CP_LEN: usize = 15; + + /// Check if the encoding part of a locale string is too long (Windows only) + #[cfg(windows)] + fn check_locale_name(locale: &str) -> bool { + if let Some(dot_pos) = locale.find('.') { + let encoding_part = &locale[dot_pos + 1..]; + // Find the end of encoding (could be followed by '@' modifier) + let encoding_len = encoding_part.find('@').unwrap_or(encoding_part.len()); + encoding_len <= MAX_CP_LEN + } else { + true + } + } + + /// Check locale names for LC_ALL (handles semicolon-separated locales) + #[cfg(windows)] + fn check_locale_name_all(locale: &str) -> bool { + for part in locale.split(';') { + if !check_locale_name(part) { + return false; + } + } + true + } + #[pyfunction] fn setlocale(args: LocaleArgs, vm: &VirtualMachine) -> PyResult { let error = error(vm); @@ -208,6 +236,21 @@ mod _locale { let result = match args.locale.flatten() { None => libc::setlocale(args.category, ptr::null()), Some(locale) => { + // On Windows, validate encoding name length + #[cfg(windows)] + { + let valid = if args.category == LC_ALL { + check_locale_name_all(locale.as_str()) + } else { + check_locale_name(locale.as_str()) + }; + if !valid { + return Err(vm.new_exception_msg( + error, + String::from("unsupported locale setting"), + )); + } + } let c_locale: CString = CString::new(locale.as_str()).map_err(|e| e.to_pyexception(vm))?; libc::setlocale(args.category, c_locale.as_ptr())