@@ -857,7 +857,7 @@ fn link_natively<'a>(
857
857
if !prog. status . success ( ) {
858
858
let mut output = prog. stderr . clone ( ) ;
859
859
output. extend_from_slice ( & prog. stdout ) ;
860
- let escaped_output = escape_string ( & output) ;
860
+ let escaped_output = escape_linker_output ( & output, flavor ) ;
861
861
// FIXME: Add UI tests for this error.
862
862
let err = errors:: LinkingFailed {
863
863
linker_path : & linker_path,
@@ -1049,6 +1049,59 @@ fn escape_string(s: &[u8]) -> String {
1049
1049
}
1050
1050
}
1051
1051
1052
+ #[ cfg( not( windows) ) ]
1053
+ fn escape_linker_output ( s : & [ u8 ] , _flavour : LinkerFlavor ) -> String {
1054
+ escape_string ( s)
1055
+ }
1056
+
1057
+ /// If the output of the msvc linker is not UTF-8 and the host is Windows,
1058
+ /// then try to convert the string from the OEM encoding.
1059
+ #[ cfg( windows) ]
1060
+ fn escape_linker_output ( s : & [ u8 ] , flavour : LinkerFlavor ) -> String {
1061
+ // This only applies to the actual MSVC linker.
1062
+ if flavour != LinkerFlavor :: Msvc ( Lld :: No ) {
1063
+ return escape_string ( s) ;
1064
+ }
1065
+ match str:: from_utf8 ( s) {
1066
+ Ok ( s) => return s. to_owned ( ) ,
1067
+ Err ( _) if s. len ( ) <= i32:: MAX as usize => {
1068
+ use windows:: Win32 :: Globalization :: {
1069
+ GetLocaleInfoEx , MultiByteToWideChar , CP_OEMCP , LOCALE_IUSEUTF8LEGACYOEMCP ,
1070
+ LOCALE_NAME_SYSTEM_DEFAULT , LOCALE_RETURN_NUMBER , MB_ERR_INVALID_CHARS ,
1071
+ } ;
1072
+ // Get the legacy system OEM code page.
1073
+ let code_page = unsafe {
1074
+ let mut cp: u32 = 0 ;
1075
+ // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
1076
+ // But the API requires us to pass the data as though it's a [u16] string.
1077
+ let len = std:: mem:: size_of :: < u32 > ( ) / std:: mem:: size_of :: < u16 > ( ) ;
1078
+ let data = std:: slice:: from_raw_parts_mut ( & mut cp as * mut u32 as * mut u16 , len) ;
1079
+ let len_written = GetLocaleInfoEx (
1080
+ LOCALE_NAME_SYSTEM_DEFAULT ,
1081
+ LOCALE_IUSEUTF8LEGACYOEMCP | LOCALE_RETURN_NUMBER ,
1082
+ Some ( data) ,
1083
+ ) ;
1084
+ if len_written as usize == len { cp } else { CP_OEMCP }
1085
+ } ;
1086
+ // Error if the string is not valid for the expected code page.
1087
+ let flags = MB_ERR_INVALID_CHARS ;
1088
+ // Call MultiByteToWideChar twice.
1089
+ // First to calculate the length then to convert the string.
1090
+ let mut len = unsafe { MultiByteToWideChar ( code_page, flags, s, None ) } ;
1091
+ if len > 0 {
1092
+ let mut utf16 = vec ! [ 0 ; len as usize ] ;
1093
+ len = unsafe { MultiByteToWideChar ( code_page, flags, s, Some ( & mut utf16) ) } ;
1094
+ if len > 0 {
1095
+ return String :: from_utf16_lossy ( & utf16[ ..len as usize ] ) ;
1096
+ }
1097
+ }
1098
+ }
1099
+ _ => { }
1100
+ } ;
1101
+ // The string is not UTF-8 and isn't valid for the OEM code page
1102
+ format ! ( "Non-UTF-8 output: {}" , s. escape_ascii( ) )
1103
+ }
1104
+
1052
1105
fn add_sanitizer_libraries ( sess : & Session , crate_type : CrateType , linker : & mut dyn Linker ) {
1053
1106
// On macOS the runtimes are distributed as dylibs which should be linked to
1054
1107
// both executables and dynamic shared objects. Everywhere else the runtimes
0 commit comments