@@ -860,7 +860,7 @@ fn link_natively<'a>(
860
860
if !prog.status.success() {
861
861
let mut output = prog.stderr.clone();
862
862
output.extend_from_slice(&prog.stdout);
863
- let escaped_output = escape_string (&output);
863
+ let escaped_output = escape_linker_output (&output, flavor );
864
864
// FIXME: Add UI tests for this error.
865
865
let err = errors::LinkingFailed {
866
866
linker_path: &linker_path,
@@ -1052,6 +1052,83 @@ fn escape_string(s: &[u8]) -> String {
1052
1052
}
1053
1053
}
1054
1054
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
+
1055
1132
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
1056
1133
// On macOS the runtimes are distributed as dylibs which should be linked to
1057
1134
// both executables and dynamic shared objects. Everywhere else the runtimes
0 commit comments