[PATCH] D42010: [LLD][COFF] Report error when file will exceed Windows maximum image size (4GB)

Colden Cullen via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 12 13:56:19 PST 2018


colden created this revision.
colden added reviewers: rnk, zturner.

Currently, when a large PE (>4 GiB) is to be produced, a crash occurs because:

1. Calling setOffset with a number greater than UINT32_MAX causes the PointerToRawData to overflow
2. When adding the symbol table to the end of the file, the last section's offset was used to calculate file size. Because this had overflowed, this number was too low, and the file created would not be large enough. This lead to the actual crash I saw, which was a buffer overrun.

This change:

1. Adds comment to setOffset, clarifying that overflow can occur, but it's somewhat safe because the error will be handled elsewhere
2. Adds file size check after all output data has been created This matches the MS link.exe error, which looks prints as: "LINK : fatal error LNK1248: image size (10000EFC9) exceeds maximum allowable size (FFFFFFFF)"
3. Changes calculate of the symbol table offset to just use the existing FileSize. This should match the previous calculations, but doesn't rely on the use of a u32 that can overflow.
4. Removes trivial usage of a magic number that bugged me while I was debugging the issue

I'm not sure how to add a test for this outside of adding 4GB of object files to the repo. If there's an easier way, let me know and I'll be happy to add a test.


Repository:
  rLLD LLVM Linker

https://reviews.llvm.org/D42010

Files:
  tools/lld/COFF/Writer.cpp


Index: tools/lld/COFF/Writer.cpp
===================================================================
--- tools/lld/COFF/Writer.cpp
+++ tools/lld/COFF/Writer.cpp
@@ -177,6 +177,9 @@
   // by the loader.
   if (Header.SizeOfRawData == 0)
     return;
+
+  // It is possible that this assignment could cause an overflow of the u32,
+  // but that should be caught by the FileSize check in OutputSection::run().
   Header.PointerToRawData = Off;
 }

@@ -295,6 +298,10 @@
   setSectionPermissions();
   createSymbolAndStringTable();

+  if (FileSize > UINT32_MAX)
+    fatal("image size (" + Twine::utohexstr(FileSize) + ") " +
+      "exceeds maximum allowable size (" + Twine::utohexstr(UINT32_MAX) + ")");
+
   // We must do this before opening the output file, as it depends on being able
   // to read the contents of the existing output file.
   PreviousBuildId = loadExistingBuildId(Config->OutputFile);
@@ -571,10 +578,8 @@
   if (OutputSymtab.empty() && Strtab.empty())
     return;

-  OutputSection *LastSection = OutputSections.back();
   // We position the symbol table to be adjacent to the end of the last section.
-  uint64_t FileOff = LastSection->getFileOff() +
-                     alignTo(LastSection->getRawSize(), SectorSize);
+  uint64_t FileOff = FileSize;
   PointerToSymbolTable = FileOff;
   FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
   FileOff += 4 + Strtab.size();
@@ -590,7 +595,7 @@
   SizeOfHeaders +=
       Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
   SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
-  uint64_t RVA = 0x1000; // The first page is kept unmapped.
+  uint64_t RVA = PageSize; // The first page is kept unmapped.
   FileSize = SizeOfHeaders;
   // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
   // the loader cannot handle holes.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D42010.129522.patch
Type: text/x-patch
Size: 1845 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180112/9f13575f/attachment.bin>


More information about the llvm-commits mailing list