From 24f3e102a678e2d102ac5660371fba1c2cfccd25 Mon Sep 17 00:00:00 2001 From: Owen Reynolds Date: Tue, 23 Jul 2019 14:44:21 +0000 Subject: [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 --- llvm/lib/Object/ArchiveWriter.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'llvm/lib/Object/ArchiveWriter.cpp') diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp index 228f6b40c5e..f12f1e521a9 100644 --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -16,6 +16,7 @@ #include "llvm/BinaryFormat/Magic.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/EndianStream.h" @@ -147,7 +148,7 @@ static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { static void printRestOfMemberHeader( raw_ostream &Out, const sys::TimePoint &ModTime, - unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { + unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) { printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // The format has only 6 chars for uid and gid. Truncate if the provided @@ -164,7 +165,7 @@ static void printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name, const sys::TimePoint &ModTime, unsigned UID, unsigned GID, unsigned Perms, - unsigned Size) { + uint64_t Size) { printWithSpacePadding(Out, Twine(Name) + "/", 16); printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); } @@ -172,8 +173,7 @@ printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name, static void printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name, const sys::TimePoint &ModTime, - unsigned UID, unsigned GID, unsigned Perms, - unsigned Size) { + unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) { uint64_t PosAfterHeader = Pos + 60 + Name.size(); // Pad so that even 64 bit object files are aligned. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8); @@ -208,7 +208,7 @@ static void printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable, StringMap &MemberNames, object::Archive::Kind Kind, bool Thin, const NewArchiveMember &M, - sys::TimePoint ModTime, unsigned Size) { + sys::TimePoint ModTime, uint64_t Size) { if (isBSDLike(Kind)) return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID, M.Perms, Size); @@ -474,8 +474,17 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); else ModTime = M.ModTime; + + uint64_t Size = Buf.getBufferSize() + MemberPadding; + if (Size > object::Archive::MaxMemberSize) { + std::string StringMsg = + "File " + M.MemberName.str() + " exceeds size limit"; + return make_error( + std::move(StringMsg), object::object_error::parse_failed); + } + printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, - ModTime, Buf.getBufferSize() + MemberPadding); + ModTime, Size); Out.flush(); Expected> Symbols = -- cgit v1.2.3