Skip to content

[lld-macho] Save all thin archive members in repro tarball #97169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 18, 2024

Conversation

BertalanD
Copy link
Member

@BertalanD BertalanD commented Jun 29, 2024

Previously, we only saved those members of thin archives into a repro
file that were actually used during linking. However, -ObjC handling
requires us to inspect all members, even those that don't end up being
loaded.

We weren't handling missing members correctly and crashed with an
"unhandled Error" failure in LLVM_ENABLE_ABI_BREAKING_CHECKS builds.

To fix this, we now eagerly load all object files and warn when
encountering missing members (in the instances where it wasn't a hard
error before). To avoid having to patch out the checks when dealing
with older repro files, the --no-warn-thin-archive-missing-members
flag is added as an escape hatch.

The repro file in llvm#94716 contains a few thin archives without their
member object files present. I couldn't figure out why this happened
(issue in repro tarball generation?), but this caused an "unhandled
Error" crash on `LLVM_ENABLE_ABI_BREAKING_CHECKS` builds.
@llvmbot
Copy link
Member

llvmbot commented Jun 29, 2024

@llvm/pr-subscribers-lld-macho

Author: Daniel Bertalan (BertalanD)

Changes

The repro file in #94716 contains a few thin archives without their member object files present. I couldn't figure out why this happened (issue in repro tarball generation?), but this caused an "unhandled Error" crash on LLVM_ENABLE_ABI_BREAKING_CHECKS builds.


Full diff: https://github.com/llvm/llvm-project/pull/97169.diff

1 Files Affected:

  • (modified) lld/MachO/Driver.cpp (+6-1)
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 9dddabcf3680c..eb64e764100b2 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -349,7 +349,12 @@ static InputFile *addFile(StringRef path, LoadType loadType,
         Error e = Error::success();
         for (const object::Archive::Child &c : file->getArchive().children(e)) {
           Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
-          if (!mb || !hasObjCSection(*mb))
+          if (!mb) {
+            llvm::consumeError(mb.takeError());
+            continue;
+          }
+
+          if (!hasObjCSection(*mb))
             continue;
           if (Error e = file->fetch(c, "-ObjC"))
             error(toString(file) + ": -ObjC failed to load archive member: " +

@llvmbot
Copy link
Member

llvmbot commented Jun 29, 2024

@llvm/pr-subscribers-lld

Author: Daniel Bertalan (BertalanD)

Changes

The repro file in #94716 contains a few thin archives without their member object files present. I couldn't figure out why this happened (issue in repro tarball generation?), but this caused an "unhandled Error" crash on LLVM_ENABLE_ABI_BREAKING_CHECKS builds.


Full diff: https://github.com/llvm/llvm-project/pull/97169.diff

1 Files Affected:

  • (modified) lld/MachO/Driver.cpp (+6-1)
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 9dddabcf3680c..eb64e764100b2 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -349,7 +349,12 @@ static InputFile *addFile(StringRef path, LoadType loadType,
         Error e = Error::success();
         for (const object::Archive::Child &c : file->getArchive().children(e)) {
           Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
-          if (!mb || !hasObjCSection(*mb))
+          if (!mb) {
+            llvm::consumeError(mb.takeError());
+            continue;
+          }
+
+          if (!hasObjCSection(*mb))
             continue;
           if (Error e = file->fetch(c, "-ObjC"))
             error(toString(file) + ": -ObjC failed to load archive member: " +

@BertalanD BertalanD requested review from nico and int3 July 5, 2024 17:47
# RUN: sed s/SYM/_unused/ %s | llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/unused.o

# RUN: cd %t; llvm-ar rcsT unused.a unused.o
## FIXME: Absolute paths don't end up relativized in the repro file.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is #97845

if (!mb || !hasObjCSection(*mb))
if (!mb) {
// Thin archives from repro tarballs can contain missing members
// if the member was not loaded later during the initial link.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a if (c.getParent()->isThin()) here to not drop valid errors?

But outside or repro files, .o files referenced from an archive being missing seems like something we probably want to diag on, hmm.

Maybe we should eagerly put all .o files referenced from thin archives into the repro file always, not just when they're referenced?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not crashing on this seems nice too though, so maybe in addition to adding all .o files from a thin archive to repro files, it'd be nice to also consumeError() here if isThin(), but emit a diag instead of doing it silently.

That seems like a good approach to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up basically going for the approach outlined here:

  • also include unused object files in the repro tarball
  • warn on missing member
  • make warning toggleable so we don't get spam on stderr when processing old repro files

My last question is what should happen if we don't find members when force-loading, i.e.:

if (Error e = file->fetch(c, reason))
error(toString(file) + ": " + reason +
" failed to load archive member: " + toString(std::move(e)));

Downgrade this to a warning too? This was not affected by the issue we're fixing (since fetch() was called unconditionally here), but if we add a user-facing option, we should be consistent about our behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me, yes.

@BertalanD BertalanD changed the title [lld-macho] Fix unchecked Error crash for thin archive missing child [lld-macho] Save all thin archive members in repro tarball Jul 15, 2024
@BertalanD BertalanD requested a review from nico July 15, 2024 17:53
@@ -349,7 +366,18 @@ static InputFile *addFile(StringRef path, LoadType loadType,
Error e = Error::success();
for (const object::Archive::Child &c : file->getArchive().children(e)) {
Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
if (!mb || !hasObjCSection(*mb))
if (!mb) {
// For a long time, only referenced object files were included in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit "included in from"

Copy link
Contributor

@nico nico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than that, looks great, thanks!

This comment was marked as outdated.

@BertalanD BertalanD merged commit 47b63cd into llvm:main Jul 18, 2024
5 of 6 checks passed
@BertalanD BertalanD deleted the thin-archive-missing branch July 18, 2024 14:26
# RUN: %lld %t/main.o %t/unused.a -ObjC --no-warn-thin-archive-missing-members -o /dev/null \
# RUN: | FileCheck %s --implicit-check-not 'warning' --allow-empty

# WARN: ld64.lld: warning: {{.*}}unused.a: -ObjC failed to open archive member: 'unused.o'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made some adjustment to hopefully make the test more conventional 2d756d9

yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
Previously, we only saved those members of thin archives into a repro
file that were actually used during linking. However, -ObjC handling
requires us to inspect all members, even those that don't end up being
loaded.

We weren't handling missing members correctly and crashed with an
"unhandled `Error`" failure in LLVM_ENABLE_ABI_BREAKING_CHECKS builds.

To fix this, we now eagerly load all object files and warn when
encountering missing members (in the instances where it wasn't a hard
error before). To avoid having to patch out the checks when dealing
with older repro files, the `--no-warn-thin-archive-missing-members`
flag is added as an escape hatch.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60250793
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants