@@ -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