[lld] r322605 - [LLD][COFF] Report error when file will exceed Windows maximum image size (4GB)

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 16 17:08:02 PST 2018


Author: ruiu
Date: Tue Jan 16 17:08:02 2018
New Revision: 322605

URL: http://llvm.org/viewvc/llvm-project?rev=322605&view=rev
Log:
[LLD][COFF] Report error when file will exceed Windows maximum image size (4GB)

Patch by Colden Cullen.

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.

Differential Revision: https://reviews.llvm.org/D42010

Modified:
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=322605&r1=322604&r2=322605&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Tue Jan 16 17:08:02 2018
@@ -177,6 +177,9 @@ void OutputSection::setFileOffset(uint64
   // 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 @@ void Writer::run() {
   setSectionPermissions();
   createSymbolAndStringTable();
 
+  if (FileSize > UINT32_MAX)
+    fatal("image size (" + Twine(FileSize) + ") " +
+        "exceeds maximum allowable size (" + Twine(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 @@ void Writer::createSymbolAndStringTable(
   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 @@ void Writer::assignAddresses() {
   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.




More information about the llvm-commits mailing list