This is an archive of the discontinued LLVM Phabricator instance.

[LLD][COFF] Fix PDB relocation on big-endian hosts
ClosedPublic

Authored by uweigand on Apr 26 2023, 10:03 AM.

Details

Summary

When running the LLD test suite on a big-endian host, the COFF/pdb-framedata.yaml test case currently fails.

As it turns out, this is because code in DebugSHandler::finish intended to relocate RvaStart entries of FDO records does not work correctly when compiled for a big-endian host.

Fixed by always reading file data in little-endian mode.

Diff Detail

Event Timeline

uweigand created this revision.Apr 26 2023, 10:03 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 26 2023, 10:03 AM
Herald added subscribers: wlei, wenlei. · View Herald Transcript
uweigand requested review of this revision.Apr 26 2023, 10:03 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 26 2023, 10:03 AM
aganea added inline comments.Apr 26 2023, 11:32 AM
lld/COFF/PDB.cpp
958

Can't we just write support::ulittle32_t rvaStart; here and static cast to a uint8_t* it below in the function call?

uweigand added inline comments.Apr 27 2023, 4:59 AM
lld/COFF/PDB.cpp
958

I guess that would be safe (in particular w.r.t. aliasing rules) if uint8_t is implemented as an unsigned char. This is probably always true in practice, but may not be absolutely guaranteed by the C++ standard. Maybe this is why the original code used a memcpy here?

Let me know if you want me to make that change. (The generated code should be identical with all modern compilers anyway.)

aganea added inline comments.
lld/COFF/PDB.cpp
958

I feel this could help future maintainers of this code. The expectations should be clear at the caller site, and it is not quite clear now why storage for uint32_t has be allocated through a uint8_t, just to memcpy it back into a ulittle32_t after the call. This all feels quite strange. If we want to avoid the casting here maybe writeAndRelocateSubsection should take a void* and let it deal with casting internally?

uweigand added inline comments.Apr 27 2023, 7:09 AM
lld/COFF/PDB.cpp
958

I mean, that memcpy is a typical pattern to work around type-based aliasing violations potentially triggering undefined behavior, so my assumption is this is why the memcpy was used here. (To be clear, the problem is not the cast as such, it's the aliasing enabled by it, and therefore it doesn't matter w.r.t. undefined behavior whether or not the cast is done in the caller or the callee.)

What would make it safe without a memcpy would be to change the type of the buf argument to a char * (or unsigned char *) in writeAndRelocateSubsection and its subroutines and access it as such consistently. [ Or, as I said, simply make and accept the assumption that uint8_t is implemented as unsigned char on all supported platforms. ]

aganea added inline comments.Apr 27 2023, 8:05 AM
lld/COFF/PDB.cpp
958

Indeed I forgot about all this type punning. Since all the other usages of writeAndRelocateSubsection don't need punning let's leave it like this. Should we add a short comment to that effect above memcpy in case it isn't obvious for everyone?

uweigand updated this revision to Diff 517573.Apr 27 2023, 8:23 AM
uweigand marked 3 inline comments as done.
uweigand added inline comments.
lld/COFF/PDB.cpp
958

Fair enough; added a comment now.

uweigand marked an inline comment as done.Apr 27 2023, 8:24 AM
aganea accepted this revision.Apr 27 2023, 8:29 AM

LGTM, thanks for the update!

This revision is now accepted and ready to land.Apr 27 2023, 8:29 AM
This revision was landed with ongoing or failed builds.Apr 27 2023, 8:48 AM
This revision was automatically updated to reflect the committed changes.