Skip to content

Commit 752c0f6

Browse files
committed
fix windows locale
1 parent b9fa405 commit 752c0f6

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

Lib/test/test_locale.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,6 @@ def test_getsetlocale_issue1813(self):
511511
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
512512
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
513513

514-
@unittest.expectedFailureIfWindows('TODO: RUSTPYTHON; Error not raised')
515514
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
516515
def test_setlocale_long_encoding(self):
517516
with self.assertRaises(locale.Error):

crates/stdlib/src/locale.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,34 @@ mod _locale {
198198
locale: OptionalArg<Option<PyStrRef>>,
199199
}
200200

201+
/// Maximum code page encoding name length on Windows
202+
#[cfg(windows)]
203+
const MAX_CP_LEN: usize = 15;
204+
205+
/// Check if the encoding part of a locale string is too long (Windows only)
206+
#[cfg(windows)]
207+
fn check_locale_name(locale: &str) -> bool {
208+
if let Some(dot_pos) = locale.find('.') {
209+
let encoding_part = &locale[dot_pos + 1..];
210+
// Find the end of encoding (could be followed by '@' modifier)
211+
let encoding_len = encoding_part.find('@').unwrap_or(encoding_part.len());
212+
encoding_len <= MAX_CP_LEN
213+
} else {
214+
true
215+
}
216+
}
217+
218+
/// Check locale names for LC_ALL (handles semicolon-separated locales)
219+
#[cfg(windows)]
220+
fn check_locale_name_all(locale: &str) -> bool {
221+
for part in locale.split(';') {
222+
if !check_locale_name(part) {
223+
return false;
224+
}
225+
}
226+
true
227+
}
228+
201229
#[pyfunction]
202230
fn setlocale(args: LocaleArgs, vm: &VirtualMachine) -> PyResult {
203231
let error = error(vm);
@@ -208,6 +236,21 @@ mod _locale {
208236
let result = match args.locale.flatten() {
209237
None => libc::setlocale(args.category, ptr::null()),
210238
Some(locale) => {
239+
// On Windows, validate encoding name length
240+
#[cfg(windows)]
241+
{
242+
let valid = if args.category == LC_ALL {
243+
check_locale_name_all(locale.as_str())
244+
} else {
245+
check_locale_name(locale.as_str())
246+
};
247+
if !valid {
248+
return Err(vm.new_exception_msg(
249+
error,
250+
String::from("unsupported locale setting"),
251+
));
252+
}
253+
}
211254
let c_locale: CString =
212255
CString::new(locale.as_str()).map_err(|e| e.to_pyexception(vm))?;
213256
libc::setlocale(args.category, c_locale.as_ptr())

0 commit comments

Comments
 (0)