[llvm] Object: Don't error out on malformed bitcode files. (PR #96848)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 28 16:52:05 PDT 2024


================
@@ -482,16 +482,47 @@ static uint64_t computeHeadersSize(object::Archive::Kind Kind,
 }
 
 static Expected<std::unique_ptr<SymbolicFile>>
-getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) {
+getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context,
+                object::Archive::Kind Kind) {
   const file_magic Type = identify_magic(Buf.getBuffer());
   // Don't attempt to read non-symbolic file types.
   if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
     return nullptr;
   if (Type == file_magic::bitcode) {
     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
         Buf, file_magic::bitcode, &Context);
-    if (!ObjOrErr)
-      return ObjOrErr.takeError();
+    // An error reading a bitcode file most likely indicates that the file
+    // was created by a compiler from the future. Normally we don't try to
+    // implement forwards compatibility for bitcode files, but when creating an
+    // archive we can implement best-effort forwards compatibility by treating
+    // the file as a blob and not creating symbol index entries for it. lld and
+    // mold ignore the archive symbol index, so provided that you use one of
+    // these linkers, LTO will work as long as lld or the gold plugin is newer
+    // than the compiler. We only ignore errors if the archive format is one
+    // that is supported by a linker that is known to ignore the index,
+    // otherwise there's no chance of this working so we may as well error out.
+    // We print a warning on read failure so that users of linkers that rely on
+    // the symbol index can diagnose the issue.
+    //
+    // This is the same behavior as GNU ar when the linker plugin returns an
+    // error when reading the input file. If the bitcode file is actually
+    // malformed, it will be diagnosed at link time.
+    if (!ObjOrErr) {
+      switch (Kind) {
+      case object::Archive::K_BSD:
+      case object::Archive::K_GNU:
+      case object::Archive::K_GNU64:
+        llvm::logAllUnhandledErrors(ObjOrErr.takeError(), llvm::errs(),
----------------
pcc wrote:

> If @dwblaikie and @jh7370 are strong about this, I think `function_ref<...> = []() { ... }` with a default argument is actually the easiest since in-tree callers do not need adjustment.

That will work well but only as long as that's the last argument. If we add another argument X to `writeArchive` and a caller wants to pass a non-default value for X they'll need to copy-paste the lambda out of the declaration. With `std::raw_ostream &Warn` they'll only need to copy-paste `llvm::errs()`.

This sort of thing is why I'm generally against expanding APIs without a concrete use case. It might seem like a simple change to add a parameter here but we could end up with unintended consequences as a result of future API evolution that adds to the maintenance burden for ourselves and other clients.

https://github.com/llvm/llvm-project/pull/96848


More information about the llvm-commits mailing list