This is an archive of the discontinued LLVM Phabricator instance.

[X86][Win64] Avoid statepoints prior to SEH epilogue
ClosedPublic

Authored by zero9178 on Feb 11 2023, 6:14 AM.

Details

Summary

This patchs purpose is very similar to https://reviews.llvm.org/D119644

The gist of the issue is that SEH unwinding has certain invariants around call instructions. One of those is that a call instruction must not be immediately followed by the function epilogue. Failing to do so leads to Windows' unwinder not recognizing the frame and skipping it when unwinding the stack.

LLVM ensures this invariant by inserting a noop after a call prior to an epilogue. The implementation however, makes the unfortunate assumption that pseudo instructions may not be calls, leading to statepoints being skipped and no noop being inserted.
This patch fixes that issue by only skipping over pseudo instructions that aren't calls.

Diff Detail

Event Timeline

zero9178 created this revision.Feb 11 2023, 6:14 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 11 2023, 6:14 AM
zero9178 requested review of this revision.Feb 11 2023, 6:14 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 11 2023, 6:14 AM
mstorsjo added a subscriber: efriedma.

The gist of the issue is that SEH unwinding has certain invariants around call instructions. One of those is that a call instruction must not be immediately followed by the function epilogue. Failing to do so leads to Windows' unwinder not recognizing the frame and skipping it when unwinding the stack.

Hmm, I was aware that this was an issue if the function ended with a non-returning call, like the testcase added in D119644, but I wasn't aware that this was an issue also for a call directly followed by the epilogue in a regular function. I would expect that to happen a lot more often.

(I'm not contradicting the statement here - I'm just not very experienced with the x86_64 SEH cases. For ARM/ARM64 SEH, these details are much more tightly defined, and such tweaks aren't luckily really needed there.)

I think the change looks reasonable, but I'm not really very familiar in this layer. I guess @rnk would be the best authority here, but he's away... Adding @efriedma who usually is knowledgeable on these things.

efriedma accepted this revision.Feb 15 2023, 1:21 PM
efriedma added a subscriber: tentzen.

LGTM

Hmm, I was aware that this was an issue if the function ended with a non-returning call, like the testcase added in D119644, but I wasn't aware that this was an issue also for a call directly followed by the epilogue in a regular function. I would expect that to happen a lot more often.

If it's actually significant to codesize, we could look into reducing the number of cases where we emit these nops. As far as I know, we really only need the padding in the case where a function has a corresponding EH pad. (Compare MSVC vs clang for void f(int*); void g1() { int z; f(&z); f(&z); } void g2() { int z; try { f(&z); f(&z); } catch (...){} }.)

This revision is now accepted and ready to land.Feb 15 2023, 1:21 PM
This revision was automatically updated to reflect the committed changes.