about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2025-02-28 22:29:49 +0800
committerGitHub <noreply@github.com>2025-02-28 22:29:49 +0800
commit61e90040db3d48eb3dffa4000ec10caad4c005b7 (patch)
tree4e4d8459a0d11d08a5ac56787c08a3fb9bc22bbf
parentd9c34a7ad207c4957ee95db9af2bb72718d6e081 (diff)
parent9f190d764f3a81fc372c76d2615fd441a129d133 (diff)
downloadrust-61e90040db3d48eb3dffa4000ec10caad4c005b7.tar.gz
rust-61e90040db3d48eb3dffa4000ec10caad4c005b7.zip
Rollup merge of #137017 - bjorn3:ignore_invalid_bitcode, r=oli-obk
Don't error when adding a staticlib with bitcode files compiled by newer LLVM

cc https://github.com/rust-lang/rust/issues/128955#issuecomment-2657811196
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs25
-rw-r--r--tests/run-make/staticlib-broken-bitcode/rmake.rs23
-rw-r--r--tests/run-make/staticlib-broken-bitcode/rust_lib.rs6
3 files changed, 51 insertions, 3 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 93553f3f364..0a161442933 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -132,14 +132,33 @@ 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 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])
+        {
+            // 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(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) as Box<io::Error>) as *mut c_void,
         }
     }
 
@@ -148,7 +167,7 @@ fn get_llvm_object_symbols(
         Box::into_raw(Box::new(io::Error::new(
             io::ErrorKind::Other,
             format!("LLVM error: {}", error.to_string_lossy()),
-        ))) as *mut c_void
+        )) as Box<io::Error>) as *mut c_void
     }
 }
 
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 00000000000..17d17c1f0f5
--- /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()
+        .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",
+        )
+        .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 00000000000..c76b0f25433
--- /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();
+}