Skip to content

Commit 451c2ef

Browse files
committed
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary: When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist). As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes. This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point). Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion Reviewed By: ruiu Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57842 llvm-svn: 353995
1 parent 1113940 commit 451c2ef

File tree

8 files changed

+115
-72
lines changed

8 files changed

+115
-72
lines changed

llvm/include/llvm/Object/ArchiveWriter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ struct NewArchiveMember {
2626
sys::TimePoint<std::chrono::seconds> ModTime;
2727
unsigned UID = 0, GID = 0, Perms = 0644;
2828

29-
bool IsNew = false;
3029
NewArchiveMember() = default;
3130
NewArchiveMember(MemoryBufferRef BufRef);
3231

@@ -37,6 +36,8 @@ struct NewArchiveMember {
3736
bool Deterministic);
3837
};
3938

39+
std::string computeArchiveRelativePath(StringRef From, StringRef To);
40+
4041
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
4142
bool WriteSymtab, object::Archive::Kind Kind,
4243
bool Deterministic, bool Thin,

llvm/lib/Object/ArchiveWriter.cpp

Lines changed: 48 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
4848
return BufOrErr.takeError();
4949

5050
NewArchiveMember M;
51-
assert(M.IsNew == false);
5251
M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
5352
M.MemberName = M.Buf->getBufferIdentifier();
5453
if (!Deterministic) {
@@ -98,7 +97,6 @@ Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
9897
return errorCodeToError(std::error_code(errno, std::generic_category()));
9998

10099
NewArchiveMember M;
101-
M.IsNew = true;
102100
M.Buf = std::move(*MemberBufferOrErr);
103101
M.MemberName = M.Buf->getBufferIdentifier();
104102
if (!Deterministic) {
@@ -191,35 +189,6 @@ static bool useStringTable(bool Thin, StringRef Name) {
191189
return Thin || Name.size() >= 16 || Name.contains('/');
192190
}
193191

194-
// Compute the relative path from From to To.
195-
static std::string computeRelativePath(StringRef From, StringRef To) {
196-
if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
197-
return To;
198-
199-
StringRef DirFrom = sys::path::parent_path(From);
200-
auto FromI = sys::path::begin(DirFrom);
201-
auto ToI = sys::path::begin(To);
202-
while (*FromI == *ToI) {
203-
++FromI;
204-
++ToI;
205-
}
206-
207-
SmallString<128> Relative;
208-
for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
209-
sys::path::append(Relative, "..");
210-
211-
for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
212-
sys::path::append(Relative, *ToI);
213-
214-
#ifdef _WIN32
215-
// Replace backslashes with slashes so that the path is portable between *nix
216-
// and Windows.
217-
std::replace(Relative.begin(), Relative.end(), '\\', '/');
218-
#endif
219-
220-
return Relative.str();
221-
}
222-
223192
static bool is64BitKind(object::Archive::Kind Kind) {
224193
switch (Kind) {
225194
case object::Archive::K_GNU:
@@ -234,27 +203,11 @@ static bool is64BitKind(object::Archive::Kind Kind) {
234203
llvm_unreachable("not supported for writting");
235204
}
236205

237-
static void addToStringTable(raw_ostream &Out, StringRef ArcName,
238-
const NewArchiveMember &M, bool Thin) {
239-
StringRef ID = M.Buf->getBufferIdentifier();
240-
if (Thin) {
241-
if (M.IsNew)
242-
Out << computeRelativePath(ArcName, ID);
243-
else
244-
Out << ID;
245-
} else
246-
Out << M.MemberName;
247-
Out << "/\n";
248-
}
249-
250-
static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
251-
raw_ostream &StringTable,
252-
StringMap<uint64_t> &MemberNames,
253-
object::Archive::Kind Kind, bool Thin,
254-
StringRef ArcName, const NewArchiveMember &M,
255-
sys::TimePoint<std::chrono::seconds> ModTime,
256-
unsigned Size) {
257-
206+
static void
207+
printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
208+
StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
209+
bool Thin, const NewArchiveMember &M,
210+
sys::TimePoint<std::chrono::seconds> ModTime, unsigned Size) {
258211
if (isBSDLike(Kind))
259212
return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
260213
M.Perms, Size);
@@ -265,12 +218,12 @@ static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
265218
uint64_t NamePos;
266219
if (Thin) {
267220
NamePos = StringTable.tell();
268-
addToStringTable(StringTable, ArcName, M, Thin);
221+
StringTable << M.MemberName << "/\n";
269222
} else {
270223
auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
271224
if (Insertion.second) {
272225
Insertion.first->second = StringTable.tell();
273-
addToStringTable(StringTable, ArcName, M, Thin);
226+
StringTable << M.MemberName << "/\n";
274227
}
275228
NamePos = Insertion.first->second;
276229
}
@@ -432,8 +385,8 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
432385

433386
static Expected<std::vector<MemberData>>
434387
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
435-
object::Archive::Kind Kind, bool Thin, StringRef ArcName,
436-
bool Deterministic, ArrayRef<NewArchiveMember> NewMembers) {
388+
object::Archive::Kind Kind, bool Thin, bool Deterministic,
389+
ArrayRef<NewArchiveMember> NewMembers) {
437390
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
438391

439392
// This ignores the symbol table, but we only need the value mod 8 and the
@@ -520,8 +473,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
520473
ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
521474
else
522475
ModTime = M.ModTime;
523-
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, ArcName,
524-
M, ModTime, Buf.getBufferSize() + MemberPadding);
476+
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
477+
ModTime, Buf.getBufferSize() + MemberPadding);
525478
Out.flush();
526479

527480
Expected<std::vector<unsigned>> Symbols =
@@ -540,11 +493,40 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
540493
return Ret;
541494
}
542495

543-
Error llvm::writeArchive(StringRef ArcName,
544-
ArrayRef<NewArchiveMember> NewMembers,
545-
bool WriteSymtab, object::Archive::Kind Kind,
546-
bool Deterministic, bool Thin,
547-
std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
496+
namespace llvm {
497+
// Compute the relative path from From to To.
498+
std::string computeArchiveRelativePath(StringRef From, StringRef To) {
499+
if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
500+
return To;
501+
502+
StringRef DirFrom = sys::path::parent_path(From);
503+
auto FromI = sys::path::begin(DirFrom);
504+
auto ToI = sys::path::begin(To);
505+
while (*FromI == *ToI) {
506+
++FromI;
507+
++ToI;
508+
}
509+
510+
SmallString<128> Relative;
511+
for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
512+
sys::path::append(Relative, "..");
513+
514+
for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
515+
sys::path::append(Relative, *ToI);
516+
517+
#ifdef _WIN32
518+
// Replace backslashes with slashes so that the path is portable between *nix
519+
// and Windows.
520+
std::replace(Relative.begin(), Relative.end(), '\\', '/');
521+
#endif
522+
523+
return Relative.str();
524+
}
525+
526+
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
527+
bool WriteSymtab, object::Archive::Kind Kind,
528+
bool Deterministic, bool Thin,
529+
std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
548530
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
549531

550532
SmallString<0> SymNamesBuf;
@@ -553,7 +535,7 @@ Error llvm::writeArchive(StringRef ArcName,
553535
raw_svector_ostream StringTable(StringTableBuf);
554536

555537
Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
556-
StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers);
538+
StringTable, SymNames, Kind, Thin, Deterministic, NewMembers);
557539
if (Error E = DataOrErr.takeError())
558540
return E;
559541
std::vector<MemberData> &Data = *DataOrErr;
@@ -630,3 +612,5 @@ Error llvm::writeArchive(StringRef ArcName,
630612

631613
return Temp->keep(ArcName);
632614
}
615+
616+
} // namespace llvm

llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
set(LLVM_LINK_COMPONENTS
2+
BinaryFormat
3+
Object
4+
Option
5+
Support
6+
)
7+
18
set(LLVM_TARGET_DEFINITIONS Options.td)
29
tablegen(LLVM Options.inc -gen-opt-parser-defs)
310
add_public_tablegen_target(LibOptionsTableGen)

llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
208208

209209
// Create an archive file.
210210
std::string OutputPath = getOutputPath(&Args, Members[0]);
211+
// llvm-lib uses relative paths for both regular and thin archives, unlike
212+
// standard GNU ar, which only uses relative paths for thin archives and
213+
// basenames for regular archives.
214+
for (NewArchiveMember &Member : Members)
215+
Member.MemberName =
216+
Saver.save(computeArchiveRelativePath(OutputPath, Member.MemberName));
217+
211218
if (Error E =
212219
writeArchive(OutputPath, Members,
213220
/*WriteSymtab=*/true, object::Archive::K_GNU,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This test creates a thin archive in a directory and adds it to a thin archive
2+
# in the parent directory. The relative path should be included when flattening
3+
# the archive.
4+
5+
RUN: mkdir -p %t/foo
6+
RUN: touch %t/foo/a.txt
7+
RUN: rm -f %t/archive.a %t/foo/archive.a
8+
9+
# These tests must be run in the same directory as %t/archive.a. cd %t is
10+
# included on each line to make debugging this test case easier.
11+
RUN: cd %t && llvm-ar rcST foo/archive.a foo/a.txt
12+
RUN: cd %t && llvm-ar rcST archive.a foo/archive.a
13+
RUN: cd %t && llvm-ar t archive.a | FileCheck %s --match-full-lines
14+
15+
CHECK: foo/a.txt

llvm/test/tools/llvm-ar/flatten-thin-archive.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# flattened members appearing together.
77

88
RUN: touch %t-a.txt %t-b.txt %t-c.txt %t-d.txt %t-e.txt
9-
RUN: rm -f %t-a-plus-b.a %t.a
9+
RUN: rm -f %t-a-plus-b.a %t-d-plus-e.a %t.a
1010
RUN: llvm-ar rcsT %t-a-plus-b.a %t-a.txt %t-b.txt
1111
RUN: llvm-ar rcs %t-d-plus-e.a %t-d.txt %t-e.txt
1212
RUN: llvm-ar rcsT %t.a %t-a-plus-b.a %t-c.txt %t-d-plus-e.a
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
RUN: rm -rf %t
2+
RUN: mkdir -p %t/foo
3+
RUN: cd %t
4+
5+
RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/obj.o %S/Inputs/a.s
6+
7+
RUN: llvm-lib -out:archive.a -llvmlibthin foo/obj.o
8+
RUN: llvm-ar t archive.a | FileCheck %s --check-prefix=PARENT-DIR --match-full-lines
9+
PARENT-DIR: foo/obj.o
10+
11+
RUN: llvm-lib -out:foo/archive.a -llvmlibthin foo/obj.o
12+
RUN: llvm-ar t foo/archive.a | FileCheck %s --check-prefix=SAME-DIR --match-full-lines
13+
SAME-DIR: foo/obj.o

llvm/tools/llvm-ar/llvm-ar.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ static std::string ArchiveName;
193193
// on the command line.
194194
static std::vector<StringRef> Members;
195195

196+
// Static buffer to hold StringRefs.
197+
static BumpPtrAllocator Alloc;
198+
196199
// Extract the member filename from the command line for the [relpos] argument
197200
// associated with a, b, and i modifiers
198201
static void getRelPos() {
@@ -545,6 +548,15 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,
545548
Expected<NewArchiveMember> NMOrErr =
546549
NewArchiveMember::getOldMember(M, Deterministic);
547550
failIfError(NMOrErr.takeError());
551+
// If the child member we're trying to add is thin, use the path relative to
552+
// the archive it's in, so the file resolves correctly.
553+
if (Thin && FlattenArchive) {
554+
StringSaver Saver(Alloc);
555+
Expected<std::string> FileNameOrErr = M.getFullName();
556+
failIfError(FileNameOrErr.takeError());
557+
NMOrErr->MemberName =
558+
Saver.save(computeArchiveRelativePath(ArchiveName, *FileNameOrErr));
559+
}
548560
if (FlattenArchive &&
549561
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
550562
Expected<std::string> FileNameOrErr = M.getFullName();
@@ -568,6 +580,13 @@ static void addMember(std::vector<NewArchiveMember> &Members,
568580
Expected<NewArchiveMember> NMOrErr =
569581
NewArchiveMember::getFile(FileName, Deterministic);
570582
failIfError(NMOrErr.takeError(), FileName);
583+
StringSaver Saver(Alloc);
584+
// For regular archives, use the basename of the object path for the member
585+
// name. For thin archives, use the full relative paths so the file resolves
586+
// correctly.
587+
NMOrErr->MemberName =
588+
Thin ? Saver.save(computeArchiveRelativePath(ArchiveName, FileName))
589+
: sys::path::filename(NMOrErr->MemberName);
571590
if (FlattenArchive &&
572591
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
573592
object::Archive &Lib = readLibrary(FileName);
@@ -581,8 +600,6 @@ static void addMember(std::vector<NewArchiveMember> &Members,
581600
return;
582601
}
583602
}
584-
// Use the basename of the object path for the member name.
585-
NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
586603
Members.push_back(std::move(*NMOrErr));
587604
}
588605

@@ -672,15 +689,15 @@ computeNewArchiveMembers(ArchiveOperation Operation,
672689
computeInsertAction(Operation, Child, Name, MemberI);
673690
switch (Action) {
674691
case IA_AddOldMember:
675-
addChildMember(Ret, Child);
692+
addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
676693
break;
677694
case IA_AddNewMember:
678695
addMember(Ret, *MemberI);
679696
break;
680697
case IA_Delete:
681698
break;
682699
case IA_MoveOldMember:
683-
addChildMember(Moved, Child);
700+
addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
684701
break;
685702
case IA_MoveNewMember:
686703
addMember(Moved, *MemberI);
@@ -899,7 +916,7 @@ static void runMRIScript() {
899916
{
900917
Error Err = Error::success();
901918
for (auto &Member : Lib.children(Err))
902-
addChildMember(NewMembers, Member);
919+
addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
903920
failIfError(std::move(Err));
904921
}
905922
break;
@@ -951,7 +968,6 @@ static bool handleGenericOption(StringRef arg) {
951968

952969
static int ar_main(int argc, char **argv) {
953970
SmallVector<const char *, 0> Argv(argv, argv + argc);
954-
BumpPtrAllocator Alloc;
955971
StringSaver Saver(Alloc);
956972
cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
957973
for (size_t i = 1; i < Argv.size(); ++i) {

0 commit comments

Comments
 (0)