Skip to content

Commit 24f3e10

Browse files
author
Owen Reynolds
committed
[llvm-ar] Fix support for archives with members larger than 4GB
llvm-ar outputs a strange error message when handling archives with members larger than 4GB due to not checking file size when passing the value as an unsigned 32 bit integer. This overflow issue caused malformed archives to be created.: https://bugs.llvm.org/show_bug.cgi?id=38058 This change allows for members above 4GB and will error in a case that is over the formats size limit, a 10 digit decimal integer. Differential Revision: https://reviews.llvm.org/D65093 llvm-svn: 366813
1 parent 4389cb9 commit 24f3e10

File tree

3 files changed

+21
-10
lines changed

3 files changed

+21
-10
lines changed

llvm/include/llvm/Object/Archive.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ class ArchiveMemberHeader {
4848
/// Get the name looking up long names.
4949
Expected<StringRef> getName(uint64_t Size) const;
5050

51-
/// Members are not larger than 4GB.
52-
Expected<uint32_t> getSize() const;
51+
Expected<uint64_t> getSize() const;
5352

5453
Expected<sys::fs::perms> getAccessMode() const;
5554
Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const;
@@ -221,6 +220,9 @@ class Archive : public Binary {
221220
Archive(MemoryBufferRef Source, Error &Err);
222221
static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source);
223222

223+
/// Size field is 10 decimal digits long
224+
static const uint64_t MaxMemberSize = 9999999999;
225+
224226
enum Kind {
225227
K_GNU,
226228
K_GNU64,

llvm/lib/Object/Archive.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
223223
return Name.drop_back(1);
224224
}
225225

226-
Expected<uint32_t> ArchiveMemberHeader::getSize() const {
227-
uint32_t Ret;
226+
Expected<uint64_t> ArchiveMemberHeader::getSize() const {
227+
uint64_t Ret;
228228
if (StringRef(ArMemHdr->Size,
229229
sizeof(ArMemHdr->Size)).rtrim(" ").getAsInteger(10, Ret)) {
230230
std::string Buf;

llvm/lib/Object/ArchiveWriter.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/BinaryFormat/Magic.h"
1717
#include "llvm/IR/LLVMContext.h"
1818
#include "llvm/Object/Archive.h"
19+
#include "llvm/Object/Error.h"
1920
#include "llvm/Object/ObjectFile.h"
2021
#include "llvm/Object/SymbolicFile.h"
2122
#include "llvm/Support/EndianStream.h"
@@ -147,7 +148,7 @@ static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
147148

148149
static void printRestOfMemberHeader(
149150
raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
150-
unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
151+
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
151152
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
152153

153154
// The format has only 6 chars for uid and gid. Truncate if the provided
@@ -164,16 +165,15 @@ static void
164165
printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
165166
const sys::TimePoint<std::chrono::seconds> &ModTime,
166167
unsigned UID, unsigned GID, unsigned Perms,
167-
unsigned Size) {
168+
uint64_t Size) {
168169
printWithSpacePadding(Out, Twine(Name) + "/", 16);
169170
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
170171
}
171172

172173
static void
173174
printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
174175
const sys::TimePoint<std::chrono::seconds> &ModTime,
175-
unsigned UID, unsigned GID, unsigned Perms,
176-
unsigned Size) {
176+
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
177177
uint64_t PosAfterHeader = Pos + 60 + Name.size();
178178
// Pad so that even 64 bit object files are aligned.
179179
unsigned Pad = OffsetToAlignment(PosAfterHeader, 8);
@@ -208,7 +208,7 @@ static void
208208
printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
209209
StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
210210
bool Thin, const NewArchiveMember &M,
211-
sys::TimePoint<std::chrono::seconds> ModTime, unsigned Size) {
211+
sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
212212
if (isBSDLike(Kind))
213213
return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
214214
M.Perms, Size);
@@ -474,8 +474,17 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
474474
ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
475475
else
476476
ModTime = M.ModTime;
477+
478+
uint64_t Size = Buf.getBufferSize() + MemberPadding;
479+
if (Size > object::Archive::MaxMemberSize) {
480+
std::string StringMsg =
481+
"File " + M.MemberName.str() + " exceeds size limit";
482+
return make_error<object::GenericBinaryError>(
483+
std::move(StringMsg), object::object_error::parse_failed);
484+
}
485+
477486
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
478-
ModTime, Buf.getBufferSize() + MemberPadding);
487+
ModTime, Size);
479488
Out.flush();
480489

481490
Expected<std::vector<unsigned>> Symbols =

0 commit comments

Comments
 (0)