Skip to content

Commit 7fdf3d7

Browse files
authored
Merge pull request #4103 from apple/🍒/austria/0bc845fe24ce
Return an error when dsymutil might produce an invalid mach-o file.
2 parents a53491f + 57c0d50 commit 7fdf3d7

File tree

2 files changed

+37
-16
lines changed

2 files changed

+37
-16
lines changed

llvm/tools/dsymutil/MachOUtils.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ static void transferSegmentAndSections(
302302
}
303303

304304
// Write the __DWARF segment load command to the output file.
305-
static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
305+
static bool createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
306306
uint64_t FileSize, unsigned NumSections,
307307
MCAsmLayout &Layout, MachObjectWriter &Writer) {
308308
Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr,
@@ -319,12 +319,16 @@ static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
319319
if (Align > 1) {
320320
VMAddr = alignTo(VMAddr, Align);
321321
FileOffset = alignTo(FileOffset, Align);
322+
if (FileOffset > UINT32_MAX)
323+
return error("section " + Sec->getName() + "'s file offset exceeds 4GB."
324+
" Refusing to produce an invalid Mach-O file.");
322325
}
323326
Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0);
324327

325328
FileOffset += Layout.getSectionAddressSize(Sec);
326329
VMAddr += Layout.getSectionAddressSize(Sec);
327330
}
331+
return true;
328332
}
329333

330334
static bool isExecutable(const object::MachOObjectFile &Obj) {
@@ -562,8 +566,9 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
562566
}
563567

564568
// Write the load command for the __DWARF segment.
565-
createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,
566-
NumDwarfSections, Layout, Writer);
569+
if (!createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,
570+
NumDwarfSections, Layout, Writer))
571+
return false;
567572

568573
assert(OutFile.tell() == LoadCommandSize + HeaderSize);
569574
OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize));

llvm/tools/dsymutil/dsymutil.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -729,24 +729,40 @@ int main(int argc, char **argv) {
729729
return EXIT_FAILURE;
730730

731731
if (NeedsTempFiles) {
732+
// Universal Mach-O files can't have an archicture slice that starts
733+
// beyond the 4GB boundary. "lipo" can creeate a 64 bit universal header,
734+
// but not all tools can parse these files so we want to return an error
735+
// if the file can't be encoded as a file with a 32 bit universal header.
736+
// To detect this, we check the size of each architecture's skinny Mach-O
737+
// file and add up the offsets. If they exceed 4GB, then we return an
738+
// error.
739+
740+
// First we compute the right offset where the first architecture will fit
741+
// followin the 32 bit universal header. The 32 bit universal header
742+
// starts with a uint32_t magic and a uint32_t number of architecture
743+
// infos. Then it is followed by 5 uint32_t values for each architecture.
744+
// So we set the start offset to the right value so we can calculate the
745+
// exact offset that the first architecture slice can start at.
746+
constexpr uint64_t MagicAndCountSize = 2 * 4;
747+
constexpr uint64_t UniversalArchInfoSize = 5 * 4;
748+
uint64_t FileOffset = MagicAndCountSize +
749+
UniversalArchInfoSize * TempFiles.size();
750+
for (const auto &File: TempFiles) {
751+
ErrorOr<vfs::Status> stat = Options.LinkOpts.VFS->status(File.path());
752+
if (!stat)
753+
break;
754+
FileOffset += stat->getSize();
755+
if (FileOffset > UINT32_MAX) {
756+
WithColor::error() << "the univesral binary has a slice with an "
757+
"offset exceeds 4GB and will produce an invalid Mach-O file.";
758+
return EXIT_FAILURE;
759+
}
760+
}
732761
if (!MachOUtils::generateUniversalBinary(TempFiles,
733762
OutputLocationOrErr->DWARFFile,
734763
Options.LinkOpts, SDKPath))
735764
return EXIT_FAILURE;
736765
}
737-
738-
// The Mach-O object file format is limited to 4GB. Make sure that we print
739-
// an error when we emit an invalid Mach-O companion file. Leave the
740-
// invalid object file around on disk for inspection.
741-
ErrorOr<vfs::Status> stat =
742-
Options.LinkOpts.VFS->status(OutputLocationOrErr->DWARFFile);
743-
if (stat) {
744-
if (stat->getSize() > std::numeric_limits<uint32_t>::max()) {
745-
WithColor::error() << "the linked debug info exceeds the 4GB Mach-O "
746-
"object file format.";
747-
return EXIT_FAILURE;
748-
}
749-
}
750766
}
751767

752768
return EXIT_SUCCESS;

0 commit comments

Comments
 (0)