aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/ArchiveWriter.cpp
diff options
context:
space:
mode:
authorpcc <peter@pcc.me.uk>2024-07-18 16:05:53 -0700
committerGitHub <noreply@github.com>2024-07-18 16:05:53 -0700
commitc675a9be63b67682477e5cbdc01c450f66bbc59a (patch)
treeb67d221cc78a743cad1e81d879e3e837fe232faa /llvm/lib/Object/ArchiveWriter.cpp
parentadacb5010f5ca6e923b3cf2d8ea47cbaab96099d (diff)
downloadllvm-c675a9be63b67682477e5cbdc01c450f66bbc59a.zip
llvm-c675a9be63b67682477e5cbdc01c450f66bbc59a.tar.gz
llvm-c675a9be63b67682477e5cbdc01c450f66bbc59a.tar.bz2
Object: Don't error out on malformed bitcode files.
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. Reviewers: MaskRay, dwblaikie, jh7370 Reviewed By: MaskRay, dwblaikie, jh7370 Pull Request: https://github.com/llvm/llvm-project/pull/96848
Diffstat (limited to 'llvm/lib/Object/ArchiveWriter.cpp')
-rw-r--r--llvm/lib/Object/ArchiveWriter.cpp64
1 files changed, 51 insertions, 13 deletions
diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp
index 34f12cf..1140455 100644
--- a/llvm/lib/Object/ArchiveWriter.cpp
+++ b/llvm/lib/Object/ArchiveWriter.cpp
@@ -482,7 +482,8 @@ 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, function_ref<void(Error)> Warn) {
const file_magic Type = identify_magic(Buf.getBuffer());
// Don't attempt to read non-symbolic file types.
if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
@@ -490,8 +491,36 @@ getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) {
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:
+ Warn(ObjOrErr.takeError());
+ return nullptr;
+ case object::Archive::K_AIXBIG:
+ case object::Archive::K_COFF:
+ case object::Archive::K_DARWIN:
+ case object::Archive::K_DARWIN64:
+ return ObjOrErr.takeError();
+ }
+ }
return std::move(*ObjOrErr);
} else {
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
@@ -751,7 +780,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
object::Archive::Kind Kind, bool Thin, bool Deterministic,
SymtabWritingMode NeedSymbols, SymMap *SymMap,
LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers,
- std::optional<bool> IsEC) {
+ std::optional<bool> IsEC, function_ref<void(Error)> Warn) {
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
uint64_t MemHeadPadSize = 0;
uint64_t Pos =
@@ -819,8 +848,10 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) {
for (const NewArchiveMember &M : NewMembers) {
- Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr =
- getSymbolicFile(M.Buf->getMemBufferRef(), Context);
+ Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = getSymbolicFile(
+ M.Buf->getMemBufferRef(), Context, Kind, [&](Error Err) {
+ Warn(createFileError(M.MemberName, std::move(Err)));
+ });
if (!SymFileOrErr)
return createFileError(M.MemberName, SymFileOrErr.takeError());
SymFiles.push_back(std::move(*SymFileOrErr));
@@ -1001,7 +1032,8 @@ Error writeArchiveToStream(raw_ostream &Out,
ArrayRef<NewArchiveMember> NewMembers,
SymtabWritingMode WriteSymtab,
object::Archive::Kind Kind, bool Deterministic,
- bool Thin, std::optional<bool> IsEC) {
+ bool Thin, std::optional<bool> IsEC,
+ function_ref<void(Error)> Warn) {
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
SmallString<0> SymNamesBuf;
@@ -1023,7 +1055,7 @@ Error writeArchiveToStream(raw_ostream &Out,
Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
- isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC);
+ isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC, Warn);
if (Error E = DataOrErr.takeError())
return E;
std::vector<MemberData> &Data = *DataOrErr;
@@ -1266,11 +1298,15 @@ Error writeArchiveToStream(raw_ostream &Out,
return Error::success();
}
+void warnToStderr(Error Err) {
+ llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "warning: ");
+}
+
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin,
std::unique_ptr<MemoryBuffer> OldArchiveBuf,
- std::optional<bool> IsEC) {
+ std::optional<bool> IsEC, function_ref<void(Error)> Warn) {
Expected<sys::fs::TempFile> Temp =
sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
if (!Temp)
@@ -1278,7 +1314,7 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
raw_fd_ostream Out(Temp->FD, false);
if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
- Deterministic, Thin, IsEC)) {
+ Deterministic, Thin, IsEC, Warn)) {
if (Error DiscardError = Temp->discard())
return joinErrors(std::move(E), std::move(DiscardError));
return E;
@@ -1302,12 +1338,14 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
Expected<std::unique_ptr<MemoryBuffer>>
writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers,
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
- bool Deterministic, bool Thin) {
+ bool Deterministic, bool Thin,
+ function_ref<void(Error)> Warn) {
SmallVector<char, 0> ArchiveBufferVector;
raw_svector_ostream ArchiveStream(ArchiveBufferVector);
- if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
- Kind, Deterministic, Thin, std::nullopt))
+ if (Error E =
+ writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, Kind,
+ Deterministic, Thin, std::nullopt, Warn))
return std::move(E);
return std::make_unique<SmallVectorMemoryBuffer>(