From 736ef0a4cee37e35caa6efb1121a776e00a9de4a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Feb 2025 09:19:10 +0000 Subject: [PATCH 1/4] Don't error when adding a staticlib with bitcode files compiled by newer LLVM --- .../rustc_codegen_llvm/src/back/archive.rs | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 93553f3f3648a..91dce57ed1ef7 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -132,23 +132,39 @@ fn get_llvm_object_symbols( if err.is_null() { return Ok(true); } else { - return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); + let error = unsafe { *Box::from_raw(err as *mut String) }; + // These are the magic constants for LLVM bitcode files: + // https://github.com/llvm/llvm-project/blob/7eadc1960d199676f04add402bb0aa6f65b7b234/llvm/lib/BinaryFormat/Magic.cpp#L90-L97 + if buf.starts_with(&[0xDE, 0xCE, 0x17, 0x0B]) || buf.starts_with(&[b'B', b'C', 0xC0, 0xDE]) + { + // For LLVM bitcode, failure to read the symbols is not fatal. The bitcode may have been + // produced by a newer LLVM version that the one linked to rustc. This is fine provided + // that the linker does use said newer LLVM version. We skip writing the symbols for the + // bitcode to the symbol table of the archive. Traditional linkers don't like this, but + // newer linkers like lld, mold and wild ignore the symbol table anyway, so if they link + // against a new enough LLVM it will work out in the end. + // LLVM's archive writer also has this same behavior of only warning about invalid + // bitcode since https://github.com/llvm/llvm-project/pull/96848 + + // We don't have access to the DiagCtxt here to produce a nice warning in the correct format. + eprintln!("warning: Failed to read symbol table from LLVM bitcode: {}", error); + return Ok(true); + } else { + return Err(io::Error::new(io::ErrorKind::Other, format!("LLVM error: {}", error))); + } } unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void { let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { Ok(()) => std::ptr::null_mut(), - Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, + Err(err) => Box::into_raw(Box::new(err.to_string()) as Box) as *mut c_void, } } unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { let error = unsafe { CStr::from_ptr(error) }; - Box::into_raw(Box::new(io::Error::new( - io::ErrorKind::Other, - format!("LLVM error: {}", error.to_string_lossy()), - ))) as *mut c_void + Box::into_raw(Box::new(error.to_string_lossy().into_owned()) as Box) as *mut c_void } } From 9147b6dd2878763208d90b41bca18d9144fd5bf8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:04:19 +0000 Subject: [PATCH 2/4] Add test --- .../staticlib-broken-bitcode/rmake.rs | 23 +++++++++++++++++++ .../staticlib-broken-bitcode/rust_lib.rs | 6 +++++ 2 files changed, 29 insertions(+) create mode 100644 tests/run-make/staticlib-broken-bitcode/rmake.rs create mode 100644 tests/run-make/staticlib-broken-bitcode/rust_lib.rs diff --git a/tests/run-make/staticlib-broken-bitcode/rmake.rs b/tests/run-make/staticlib-broken-bitcode/rmake.rs new file mode 100644 index 0000000000000..f8c61d7081910 --- /dev/null +++ b/tests/run-make/staticlib-broken-bitcode/rmake.rs @@ -0,0 +1,23 @@ +// Regression test for https://github.com/rust-lang/rust/issues/128955#issuecomment-2657811196 +// which checks that rustc can read an archive containing LLVM bitcode with a +// newer version from the one rustc links against. +use run_make_support::{llvm_ar, path, rfs, rustc, static_lib_name}; + +fn main() { + rfs::create_dir("archive"); + + let mut bitcode = b"BC\xC0\xDE".to_vec(); + bitcode.extend(std::iter::repeat(b'a').take(50)); + rfs::write("archive/invalid_bitcode.o", &bitcode); + + llvm_ar() + .obj_to_thin_ar() + .output_input( + path("archive").join(static_lib_name("thin_archive")), + "archive/invalid_bitcode.o", + ) + .run(); + + // Build an rlib which includes the members of this thin archive + rustc().input("rust_lib.rs").library_search_path("archive").run(); +} diff --git a/tests/run-make/staticlib-broken-bitcode/rust_lib.rs b/tests/run-make/staticlib-broken-bitcode/rust_lib.rs new file mode 100644 index 0000000000000..c76b0f2543376 --- /dev/null +++ b/tests/run-make/staticlib-broken-bitcode/rust_lib.rs @@ -0,0 +1,6 @@ +#![crate_type = "rlib"] + +#[link(name = "thin_archive", kind = "static")] +extern "C" { + pub fn simple_fn(); +} From ec451661660193bba32765b7d08b1d3ba1d21383 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:30:17 +0000 Subject: [PATCH 3/4] Tell llvm-ar to not create a symbol table --- tests/run-make/staticlib-broken-bitcode/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/staticlib-broken-bitcode/rmake.rs b/tests/run-make/staticlib-broken-bitcode/rmake.rs index f8c61d7081910..17d17c1f0f5e8 100644 --- a/tests/run-make/staticlib-broken-bitcode/rmake.rs +++ b/tests/run-make/staticlib-broken-bitcode/rmake.rs @@ -11,7 +11,7 @@ fn main() { rfs::write("archive/invalid_bitcode.o", &bitcode); llvm_ar() - .obj_to_thin_ar() + .arg("rcuS") // like obj_to_ar() except skips creating a symbol table .output_input( path("archive").join(static_lib_name("thin_archive")), "archive/invalid_bitcode.o", From 9f190d764f3a81fc372c76d2615fd441a129d133 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 26 Feb 2025 13:45:35 +0000 Subject: [PATCH 4/4] Restore usage of io::Error --- compiler/rustc_codegen_llvm/src/back/archive.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 91dce57ed1ef7..0a161442933ab 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -132,7 +132,7 @@ fn get_llvm_object_symbols( if err.is_null() { return Ok(true); } else { - let error = unsafe { *Box::from_raw(err as *mut String) }; + let error = unsafe { *Box::from_raw(err as *mut io::Error) }; // These are the magic constants for LLVM bitcode files: // https://github.com/llvm/llvm-project/blob/7eadc1960d199676f04add402bb0aa6f65b7b234/llvm/lib/BinaryFormat/Magic.cpp#L90-L97 if buf.starts_with(&[0xDE, 0xCE, 0x17, 0x0B]) || buf.starts_with(&[b'B', b'C', 0xC0, 0xDE]) @@ -150,7 +150,7 @@ fn get_llvm_object_symbols( eprintln!("warning: Failed to read symbol table from LLVM bitcode: {}", error); return Ok(true); } else { - return Err(io::Error::new(io::ErrorKind::Other, format!("LLVM error: {}", error))); + return Err(error); } } @@ -158,13 +158,16 @@ fn get_llvm_object_symbols( let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { Ok(()) => std::ptr::null_mut(), - Err(err) => Box::into_raw(Box::new(err.to_string()) as Box) as *mut c_void, + Err(err) => Box::into_raw(Box::new(err) as Box) as *mut c_void, } } unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { let error = unsafe { CStr::from_ptr(error) }; - Box::into_raw(Box::new(error.to_string_lossy().into_owned()) as Box) as *mut c_void + Box::into_raw(Box::new(io::Error::new( + io::ErrorKind::Other, + format!("LLVM error: {}", error.to_string_lossy()), + )) as Box) as *mut c_void } }