@@ -860,7 +860,7 @@ fn link_natively<'a>(
860860 if !prog. status . success ( ) {
861861 let mut output = prog. stderr . clone ( ) ;
862862 output. extend_from_slice ( & prog. stdout ) ;
863- let escaped_output = escape_string ( & output) ;
863+ let escaped_output = escape_linker_output ( & output, flavor ) ;
864864 // FIXME: Add UI tests for this error.
865865 let err = errors:: LinkingFailed {
866866 linker_path : & linker_path,
@@ -1052,6 +1052,83 @@ fn escape_string(s: &[u8]) -> String {
10521052 }
10531053}
10541054
1055+ #[ cfg( not( windows) ) ]
1056+ fn escape_linker_output ( s : & [ u8 ] , _flavour : LinkerFlavor ) -> String {
1057+ escape_string ( s)
1058+ }
1059+
1060+ /// If the output of the msvc linker is not UTF-8 and the host is Windows,
1061+ /// then try to convert the string from the OEM encoding.
1062+ #[ cfg( windows) ]
1063+ fn escape_linker_output ( s : & [ u8 ] , flavour : LinkerFlavor ) -> String {
1064+ // This only applies to the actual MSVC linker.
1065+ if flavour != LinkerFlavor :: Msvc ( Lld :: No ) {
1066+ return escape_string ( s) ;
1067+ }
1068+ match str:: from_utf8 ( s) {
1069+ Ok ( s) => return s. to_owned ( ) ,
1070+ Err ( _) => match win:: locale_byte_str_to_string ( s, win:: oem_code_page ( ) ) {
1071+ Some ( s) => s,
1072+ // The string is not UTF-8 and isn't valid for the OEM code page
1073+ None => format ! ( "Non-UTF-8 output: {}" , s. escape_ascii( ) ) ,
1074+ } ,
1075+ }
1076+ }
1077+
1078+ /// Wrappers around the Windows API.
1079+ #[ cfg( windows) ]
1080+ mod win {
1081+ use windows:: Win32 :: Globalization :: {
1082+ GetLocaleInfoEx , MultiByteToWideChar , CP_OEMCP , LOCALE_IUSEUTF8LEGACYOEMCP ,
1083+ LOCALE_NAME_SYSTEM_DEFAULT , LOCALE_RETURN_NUMBER , MB_ERR_INVALID_CHARS ,
1084+ } ;
1085+
1086+ /// Get the Windows system OEM code page. This is most notably the code page
1087+ /// used for link.exe's output.
1088+ pub fn oem_code_page ( ) -> u32 {
1089+ unsafe {
1090+ let mut cp: u32 = 0 ;
1091+ // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
1092+ // But the API requires us to pass the data as though it's a [u16] string.
1093+ let len = std:: mem:: size_of :: < u32 > ( ) / std:: mem:: size_of :: < u16 > ( ) ;
1094+ let data = std:: slice:: from_raw_parts_mut ( & mut cp as * mut u32 as * mut u16 , len) ;
1095+ let len_written = GetLocaleInfoEx (
1096+ LOCALE_NAME_SYSTEM_DEFAULT ,
1097+ LOCALE_IUSEUTF8LEGACYOEMCP | LOCALE_RETURN_NUMBER ,
1098+ Some ( data) ,
1099+ ) ;
1100+ if len_written as usize == len { cp } else { CP_OEMCP }
1101+ }
1102+ }
1103+ /// Try to convert a multi-byte string to a UTF-8 string using the given code page
1104+ /// The string does not need to be null terminated.
1105+ ///
1106+ /// This is implemented as a wrapper around `MultiByteToWideChar`.
1107+ /// See <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar>
1108+ ///
1109+ /// It will fail if the multi-byte string is longer than `i32::MAX` or if it contains
1110+ /// any invalid bytes for the expected encoding.
1111+ pub fn locale_byte_str_to_string ( s : & [ u8 ] , code_page : u32 ) -> Option < String > {
1112+ // `MultiByteToWideChar` requires a length to be a "positive integer".
1113+ if s. len ( ) > isize:: MAX as usize {
1114+ return None ;
1115+ }
1116+ // Error if the string is not valid for the expected code page.
1117+ let flags = MB_ERR_INVALID_CHARS ;
1118+ // Call MultiByteToWideChar twice.
1119+ // First to calculate the length then to convert the string.
1120+ let mut len = unsafe { MultiByteToWideChar ( code_page, flags, s, None ) } ;
1121+ if len > 0 {
1122+ let mut utf16 = vec ! [ 0 ; len as usize ] ;
1123+ len = unsafe { MultiByteToWideChar ( code_page, flags, s, Some ( & mut utf16) ) } ;
1124+ if len > 0 {
1125+ return utf16. get ( ..len as usize ) . map ( String :: from_utf16_lossy) ;
1126+ }
1127+ }
1128+ None
1129+ }
1130+ }
1131+
10551132fn add_sanitizer_libraries ( sess : & Session , crate_type : CrateType , linker : & mut dyn Linker ) {
10561133 // On macOS the runtimes are distributed as dylibs which should be linked to
10571134 // both executables and dynamic shared objects. Everywhere else the runtimes
0 commit comments