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

Authored by colden on Jan 12 2018, 1:56 PM.



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.

Diff Detail

colden created this revision.Jan 12 2018, 1:56 PM
ruiu added a comment.Jan 12 2018, 2:54 PM

Generally looking fine.

302 ↗(On Diff #129522)

I feel printing out a file size in hexadecimal is somewhat unusual. Maybe decimal is better?

colden added inline comments.Jan 12 2018, 3:30 PM
302 ↗(On Diff #129522)

Yeah, I was kind of surprised to see the MS linker does hex. I think you're right though, I'll switch it back.

colden updated this revision to Diff 129729.Jan 12 2018, 4:20 PM

Switch error message to use decimal format from hex.

ruiu added inline comments.Jan 12 2018, 4:24 PM
303–305 ↗(On Diff #129729)

I believe you can do

fatal("image size ("+ Twine(FileSize) + ") exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");

colden updated this revision to Diff 129735.Jan 12 2018, 4:42 PM

Turns out you can do the easier thing

ruiu accepted this revision.Jan 12 2018, 4:45 PM

LGTM. Thanks!

This revision is now accepted and ready to land.Jan 12 2018, 4:45 PM

Thanks for the quick reviews!

Would you mind committing this for me?

Bump, could someone submit this for me?

rnk added inline comments.Jan 16 2018, 9:22 AM
303–305 ↗(On Diff #129729)

Apologies in advance for nit picking, but why not say something more human readable like "4GB"?

colden added inline comments.Jan 16 2018, 9:26 AM
303–305 ↗(On Diff #129729)

No problem, I'm happy to entertain nits :)

If we do this, I think we should represent the current size in GB as well. Printing two numbers that are not directly comparable would drive me nuts as a user. Is there an easy conversion function for this somewhere, or should I just static_cast to float and divide by 1073741824?

rnk added inline comments.Jan 16 2018, 10:34 AM
303–305 ↗(On Diff #129729)

Nevermind, I think comparability is a great reason to keep this as it is.

This revision was automatically updated to reflect the committed changes.