Skip to content

Commit a20168d

Browse files
committed
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an old archiver, containing an unsupported attribute, or an ELF file with a malformed symbol table, the archiver would throw away the error and simply add the member to the archive without any symbol entries. This meant that the resultant archive could be silently unusable when not using --whole-archive, and result in unexpected undefined symbols. This change fixes this issue by addressing two FIXMEs and only throwing away not-an-object errors. However, this meant that some LLD tests which didn't need symbol tables and were using invalid members deliberately to test the linker's malformed input handling no longer worked, so this patch also stops the archiver from looking for symbols in an object if it doesn't require a symbol table, and updates the tests accordingly. Differential Revision: https://reviews.llvm.org/D88288 Reviewed by: grimar, rupprecht, MaskRay
1 parent 5101e7e commit a20168d

File tree

7 files changed

+116
-34
lines changed

7 files changed

+116
-34
lines changed

lld/test/ELF/invalid/data-encoding.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Check we report this.
55

66
# RUN: yaml2obj %s -o %t.o
7-
# RUN: llvm-ar rcs %t.a %t.o
7+
# RUN: llvm-ar rcS %t.a %t.o
88

99
# RUN: not ld.lld --whole-archive %t.a -o /dev/null 2>&1 | FileCheck %s
1010
# CHECK: {{.*}}.a({{.*}}.o): corrupted ELF file: invalid data encoding

lld/test/ELF/invalid/invalid-file-class.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
## EV_CURRENT(1), ELFOSABI_LINUX(3), <padding zero bytes>, ET_REL(1), EM_NONE(0)
1212
# RUN: echo -e -n "\x7f\x45\x4c\x46\x00\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00" > %t/invalid.o
1313

14-
# RUN: llvm-ar --format=gnu cr %t/invalid-class.a %t/invalid.o
14+
# RUN: llvm-ar --format=gnu crS %t/invalid-class.a %t/invalid.o
1515
# RUN: not ld.lld -whole-archive %t/invalid-class.a -o /dev/null 2>&1 | FileCheck %s
1616
# CHECK: invalid-class.a(invalid.o): corrupted ELF file: invalid file class
1717

llvm/include/llvm/Object/SymbolicFile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ class SymbolicFile : public Binary {
173173
static bool classof(const Binary *v) {
174174
return v->isSymbolic();
175175
}
176+
177+
static bool isSymbolicFile(file_magic Type, const LLVMContext *Context);
176178
};
177179

178180
inline BasicSymbolRef::BasicSymbolRef(DataRefImpl SymbolP,

llvm/lib/Object/ArchiveWriter.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -359,22 +359,21 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
359359
// reference to it, thus SymbolicFile should be destroyed first.
360360
LLVMContext Context;
361361
std::unique_ptr<object::SymbolicFile> Obj;
362-
if (identify_magic(Buf.getBuffer()) == file_magic::bitcode) {
362+
363+
const file_magic Type = identify_magic(Buf.getBuffer());
364+
// Treat unsupported file types as having no symbols.
365+
if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
366+
return Ret;
367+
if (Type == file_magic::bitcode) {
363368
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
364369
Buf, file_magic::bitcode, &Context);
365-
if (!ObjOrErr) {
366-
// FIXME: check only for "not an object file" errors.
367-
consumeError(ObjOrErr.takeError());
368-
return Ret;
369-
}
370+
if (!ObjOrErr)
371+
return ObjOrErr.takeError();
370372
Obj = std::move(*ObjOrErr);
371373
} else {
372374
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
373-
if (!ObjOrErr) {
374-
// FIXME: check only for "not an object file" errors.
375-
consumeError(ObjOrErr.takeError());
376-
return Ret;
377-
}
375+
if (!ObjOrErr)
376+
return ObjOrErr.takeError();
378377
Obj = std::move(*ObjOrErr);
379378
}
380379

@@ -393,7 +392,7 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
393392
static Expected<std::vector<MemberData>>
394393
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
395394
object::Archive::Kind Kind, bool Thin, bool Deterministic,
396-
ArrayRef<NewArchiveMember> NewMembers) {
395+
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
397396
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
398397

399398
// This ignores the symbol table, but we only need the value mod 8 and the
@@ -494,13 +493,17 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
494493
ModTime, Size);
495494
Out.flush();
496495

497-
Expected<std::vector<unsigned>> Symbols =
498-
getSymbols(Buf, SymNames, HasObject);
499-
if (auto E = Symbols.takeError())
500-
return std::move(E);
496+
std::vector<unsigned> Symbols;
497+
if (NeedSymbols) {
498+
Expected<std::vector<unsigned>> SymbolsOrErr =
499+
getSymbols(Buf, SymNames, HasObject);
500+
if (auto E = SymbolsOrErr.takeError())
501+
return std::move(E);
502+
Symbols = std::move(*SymbolsOrErr);
503+
}
501504

502505
Pos += Header.size() + Data.size() + Padding.size();
503-
Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding});
506+
Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding});
504507
}
505508
// If there are no symbols, emit an empty symbol table, to satisfy Solaris
506509
// tools, older versions of which expect a symbol table in a non-empty
@@ -564,8 +567,9 @@ static Error writeArchiveToStream(raw_ostream &Out,
564567
SmallString<0> StringTableBuf;
565568
raw_svector_ostream StringTable(StringTableBuf);
566569

567-
Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
568-
StringTable, SymNames, Kind, Thin, Deterministic, NewMembers);
570+
Expected<std::vector<MemberData>> DataOrErr =
571+
computeMemberData(StringTable, SymNames, Kind, Thin, Deterministic,
572+
WriteSymtab, NewMembers);
569573
if (Error E = DataOrErr.takeError())
570574
return E;
571575
std::vector<MemberData> &Data = *DataOrErr;

llvm/lib/Object/SymbolicFile.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,14 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
4141
if (Type == file_magic::unknown)
4242
Type = identify_magic(Data);
4343

44+
if (!isSymbolicFile(Type, Context))
45+
return errorCodeToError(object_error::invalid_file_type);
46+
4447
switch (Type) {
4548
case file_magic::bitcode:
46-
if (Context)
47-
return IRObjectFile::create(Object, *Context);
48-
LLVM_FALLTHROUGH;
49-
case file_magic::unknown:
50-
case file_magic::archive:
51-
case file_magic::coff_cl_gl_object:
52-
case file_magic::macho_universal_binary:
53-
case file_magic::windows_resource:
54-
case file_magic::pdb:
55-
case file_magic::minidump:
56-
case file_magic::tapi_file:
57-
return errorCodeToError(object_error::invalid_file_type);
49+
// Context is guaranteed to be non-null here, because bitcode magic only
50+
// indicates a symbolic file when Context is non-null.
51+
return IRObjectFile::create(Object, *Context);
5852
case file_magic::elf:
5953
case file_magic::elf_executable:
6054
case file_magic::elf_shared_object:
@@ -95,6 +89,39 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
9589
MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()),
9690
*Context);
9791
}
92+
default:
93+
llvm_unreachable("Unexpected Binary File Type");
94+
}
95+
}
96+
97+
bool SymbolicFile::isSymbolicFile(file_magic Type, const LLVMContext *Context) {
98+
switch (Type) {
99+
case file_magic::bitcode:
100+
return Context != nullptr;
101+
case file_magic::elf:
102+
case file_magic::elf_executable:
103+
case file_magic::elf_shared_object:
104+
case file_magic::elf_core:
105+
case file_magic::macho_executable:
106+
case file_magic::macho_fixed_virtual_memory_shared_lib:
107+
case file_magic::macho_core:
108+
case file_magic::macho_preload_executable:
109+
case file_magic::macho_dynamically_linked_shared_lib:
110+
case file_magic::macho_dynamic_linker:
111+
case file_magic::macho_bundle:
112+
case file_magic::macho_dynamically_linked_shared_lib_stub:
113+
case file_magic::macho_dsym_companion:
114+
case file_magic::macho_kext_bundle:
115+
case file_magic::pecoff_executable:
116+
case file_magic::xcoff_object_32:
117+
case file_magic::xcoff_object_64:
118+
case file_magic::wasm_object:
119+
case file_magic::coff_import_library:
120+
case file_magic::elf_relocatable:
121+
case file_magic::macho_object:
122+
case file_magic::coff_object:
123+
return true;
124+
default:
125+
return false;
98126
}
99-
llvm_unreachable("Unexpected Binary File Type");
100127
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Show that the archive library emits error messages when adding malformed
2+
## objects.
3+
4+
# RUN: rm -rf %t.dir
5+
# RUN: split-file %s %t.dir
6+
# RUN: cd %t.dir
7+
8+
## Malformed bitcode object.
9+
# RUN: llvm-as input.ll -o input.bc
10+
# RUN: %python -c "with open('input.bc', 'a') as f: f.truncate(10)"
11+
# RUN: not llvm-ar rc bad.a input.bc 2>&1 | FileCheck %s --check-prefix=ERR1
12+
13+
# ERR1: error: bad.a: Invalid bitcode signature
14+
15+
## Non-bitcode malformed file.
16+
# RUN: yaml2obj input.yaml -o input.o
17+
# RUN: not llvm-ar rc bad.a input.o 2>&1 | FileCheck %s --check-prefix=ERR2
18+
19+
# ERR2: error: bad.a: section header table goes past the end of the file: e_shoff = 0x9999
20+
21+
## Don't emit an error if the symbol table is not required.
22+
# RUN: llvm-ar rcS good.a input.o input.bc
23+
# RUN: llvm-ar t good.a | FileCheck %s --check-prefix=CONTENTS
24+
25+
# CONTENTS: input.o
26+
# CONTENTS-NEXT: input.bc
27+
28+
#--- input.ll
29+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
30+
target triple = "x86_64-pc-linux"
31+
32+
#--- input.yaml
33+
--- !ELF
34+
FileHeader:
35+
Class: ELFCLASS64
36+
Data: ELFDATA2LSB
37+
Type: ET_REL
38+
EShOff: 0x9999
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## Show that the archive library does not emit an error or add any symbols to
2+
## the archive symbol table, when it encounters an unknown file type, but still
3+
## adds the file to the archive.
4+
5+
# RUN: echo something > %t
6+
# RUN: rm -f %t.a
7+
# RUN: llvm-ar rc %t.a %t
8+
# RUN: llvm-ar t %t.a | FileCheck %s --check-prefix=CONTENTS -DFILE=%basename_t
9+
# RUN: llvm-nm --print-armap %t.a | FileCheck %s --allow-empty --implicit-check-not={{.}}
10+
11+
# CONTENTS: [[FILE]]

0 commit comments

Comments
 (0)