@@ -410,36 +410,57 @@ pub(crate) mod _thread {
410410 vm. state . stop_the_world . reset_stats ( ) ;
411411 }
412412
413- #[ cfg( any( unix , windows ) ) ]
413+ #[ cfg( any( windows , target_os = "linux" , target_os = "macos" ) ) ]
414414 #[ pyattr]
415415 const _NAME_MAXLEN: usize = host_thread:: NAME_MAXLEN ;
416416
417+ /// Truncate a Windows thread name to `_NAME_MAXLEN` UTF-16 code units,
418+ /// dropping a trailing non-BMP character that would not fit as a pair.
419+ #[ cfg( windows) ]
420+ fn truncate_thread_name_wide ( name : & crate :: common:: wtf8:: Wtf8 ) -> Vec < u16 > {
421+ let encoded: Vec < u16 > = name. encode_wide ( ) . collect ( ) ;
422+ let mut units = Vec :: new ( ) ;
423+ let mut i = 0 ;
424+ while i < encoded. len ( ) {
425+ let unit = encoded[ i] ;
426+ if unit == 0 {
427+ break ;
428+ }
429+ let width = match encoded. get ( i + 1 ) {
430+ Some ( & lo)
431+ if ( 0xD800 ..=0xDBFF ) . contains ( & unit) && ( 0xDC00 ..=0xDFFF ) . contains ( & lo) =>
432+ {
433+ 2
434+ }
435+ _ => 1 ,
436+ } ;
437+ if units. len ( ) + width > host_thread:: NAME_MAXLEN {
438+ break ;
439+ }
440+ units. extend_from_slice ( & encoded[ i..i + width] ) ;
441+ i += width;
442+ }
443+ units. push ( 0 ) ;
444+ units
445+ }
446+
447+ #[ cfg( any( windows, target_os = "linux" , target_os = "macos" ) ) ]
417448 #[ pyfunction]
418449 fn set_name ( name : PyStrRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
419450 #[ cfg( windows) ]
420451 {
421- let mut units = Vec :: new ( ) ;
422- for unit in name. as_wtf8 ( ) . encode_wide ( ) {
423- if unit == 0 || units. len ( ) >= host_thread:: NAME_MAXLEN {
424- break ;
425- }
426- units. push ( unit) ;
427- }
428- units. push ( 0 ) ;
452+ let units = truncate_thread_name_wide ( name. as_wtf8 ( ) ) ;
429453 host_thread:: set_current_thread_name_wide ( & units) . map_err ( |e| e. to_pyexception ( vm) ) ?;
430454 }
431455 #[ cfg( any( target_os = "linux" , target_os = "macos" ) ) ]
432456 {
433457 let os_name = vm. fsencode ( & name) ?;
434458 host_thread:: set_current_thread_name_bytes ( os_name. as_encoded_bytes ( ) ) ;
435459 }
436- #[ cfg( not( any( windows, target_os = "linux" , target_os = "macos" ) ) ) ]
437- {
438- let _ = ( name, vm) ;
439- }
440460 Ok ( ( ) )
441461 }
442462
463+ #[ cfg( any( windows, target_os = "linux" , target_os = "macos" ) ) ]
443464 #[ pyfunction( name = "_get_name" ) ]
444465 fn get_name ( vm : & VirtualMachine ) -> PyResult {
445466 #[ cfg( windows) ]
@@ -456,10 +477,6 @@ pub(crate) mod _thread {
456477 let os = unsafe { std:: ffi:: OsString :: from_encoded_bytes_unchecked ( bytes) } ;
457478 Ok ( vm. fsdecode ( os) . into ( ) )
458479 }
459- #[ cfg( not( any( windows, target_os = "linux" , target_os = "macos" ) ) ) ]
460- {
461- Ok ( vm. ctx . new_str ( "" ) . into ( ) )
462- }
463480 }
464481
465482 /// Get OS-level thread ID (pthread_self on Unix, GetCurrentThreadId on Windows)
0 commit comments