This is an archive of the discontinued LLVM Phabricator instance.

Fix SEH table addresses for Windows
ClosedPublic

Authored by dpaoliello on Aug 9 2021, 2:57 PM.

Details

Summary

Issue Details:
The addresses for SEH tables for Windows are incorrect as 1 was unconditionally being added to all addresses. +1 is required for the SEH end address (as it is exclusive), but the SEH start addresses is inclusive and so should be used as-is.

In the IP2State tables, the addresses are +1 for AMD64 to handle the return address for a call being after the actual call instruction but are as-is for ARM and ARM64 as the StateFromIp function in the VC runtime automatically takes this into account and adjusts the address that is it looking up.

Fix Details:

  • Split the getLabel function into two: getLabel (used for the SEH start address and ARM+ARM64 IP2State addresses) and getLabelPlusOne (for the SEH end address, and AMD64 IP2State addresses).

Diff Detail

Event Timeline

dpaoliello created this revision.Aug 9 2021, 2:57 PM
dpaoliello requested review of this revision.Aug 9 2021, 2:57 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 9 2021, 2:57 PM
efriedma edited reviewers, added: rnk, mstorsjo, hans; removed: asl, ssijaric.Aug 9 2021, 3:18 PM
rnk requested changes to this revision.Aug 9 2021, 7:37 PM
rnk added inline comments.
llvm/lib/CodeGen/AsmPrinter/WinException.cpp
336

It seems that after several rounds of refactoring, there are no comments here explaining why this happens. :(

668

Arguably, this is the special case that opens a range but does not end one, so the modification would be here.

963

This is the other call site of getLabel for C++.

llvm/test/CodeGen/WinEH/wineh-noret-cleanup.ll
49

These changes are incorrect. The C++ ip2state table doesn't have a begin/end pair, it has a series of labels. When an exception is thrown from the last instruction in a range, these labels must be strictly greater than the return address.

Fortunately, there are no single-byte instructions that can throw a C++ exception, so the entire table can be biased forwards by one byte.

This revision now requires changes to proceed.Aug 9 2021, 7:37 PM
dpaoliello retitled this revision from Fix SEH and IP2State table addresses for Windows to Fix SEH table addresses for Windows.
dpaoliello edited the summary of this revision. (Show Details)

Only avoid +1 for SEH start addresses

dpaoliello marked 4 inline comments as done.Aug 10 2021, 1:07 PM
dpaoliello added inline comments.
llvm/test/CodeGen/WinEH/wineh-noret-cleanup.ll
49

Ah, ok, this makes sense:
In all of the caller frames we need to consider the calling instruction, not the instruction that we will be returning to.
For the throwing frame itself, we're off by 1, however the address of the throwing instruction is always less than the next IP2State transition since there is no one byte throwing instruction.

rnk added inline comments.Aug 10 2021, 2:18 PM
llvm/lib/CodeGen/AsmPrinter/WinException.cpp
333

I think you've lost this ARM change unintentionally. For AArch64, we don't bias the label forward. However, that seems wrong to me based on MSVC's output:
https://gcc.godbolt.org/z/3TxMfqoTh

MSVC inserts a nop instruction after the bl instruction implementing the call, and if I read the ip2state table correctly, the ip2state entry is the address following the nop instruction. So, I strongly suspect there is a bug here for ARM, but it's an existing problem.

You can see in the history that this code changed in 2018, we used to have a getLabelPlusOne method, but it was renamed:
https://reviews.llvm.org/D50166

dpaoliello marked an inline comment as done.
dpaoliello edited the summary of this revision. (Show Details)

Fix ARM IP2State

dpaoliello marked an inline comment as done.Aug 11 2021, 12:06 PM
dpaoliello added inline comments.
llvm/lib/CodeGen/AsmPrinter/WinException.cpp
333

I've dug into this a bit more: ARM and ARM64 don't need the +1 as the StateFromIp function in the VC Runtime adjusts the input address to compensate for call-return-address issue, whereas it does not for AMD64 (probably for legacy reasons).

dpaoliello edited the summary of this revision. (Show Details)Aug 11 2021, 12:06 PM
dpaoliello edited the summary of this revision. (Show Details)
rnk accepted this revision.Aug 11 2021, 12:16 PM

lgtm

llvm/lib/CodeGen/AsmPrinter/WinException.cpp
670

So, this *will* be a behavior change for ARM. Is that desired? Are there issues with adding one to ARM PCs? It sets the thumb bit, but maybe that doesn't matter to __C_specific_handler on ARM. Neither ARM ISA has single byte instructions (right?), so adding one isn't likely to accidentally cause an exception from the next instruction to go to the wrong handler.

955–958

Truthfully, it feels to me like this is an x64-specific bug. If Windows were to be ported to a new architecture in five years, I bet they'd stick with the ARM behavior, and we wouldn't do the +1. However, that's all very hypothetical, I don't see a need for any code changes.

This revision is now accepted and ready to land.Aug 11 2021, 12:16 PM
dpaoliello marked 3 inline comments as done.Aug 11 2021, 12:54 PM
dpaoliello added inline comments.
llvm/lib/CodeGen/AsmPrinter/WinException.cpp
670

__C_specific_handler has the same call-return-address compensation on ARM/ARM64 as FrameFromIp. That being said, this change is desired as the end address is exclusive, so we should +1 it to make sure that the comparison works correctly.

955–958

Sorry, I don't really have any explanation here either ¯\_(ツ)_/¯

dpaoliello marked 2 inline comments as done.Aug 11 2021, 1:12 PM
dpaoliello added inline comments.
llvm/lib/CodeGen/AsmPrinter/WinException.h
43

@rnk Would you prefer if I followed the existing casing here, or used the casing that clang-tidy suggests?

rnk added inline comments.Aug 11 2021, 2:51 PM
llvm/lib/CodeGen/AsmPrinter/WinException.h
43

Let's stay consistent with what's here and ignore clang-tidy for now.

@rnk Can you please merge this in?

@rnk Who can help merge this in?

@rnk Who can help merge this in?

I might have time to apply, run tests and push it - can you provide the git author line, ie “Real Name <email@address>” to use for the commit?

@rnk Who can help merge this in?

I might have time to apply, run tests and push it - can you provide the git author line, ie “Real Name <email@address>” to use for the commit?

Daniel Paoliello <danpao@microsoft.com>

This revision was landed with ongoing or failed builds.Aug 20 2021, 12:32 PM
This revision was automatically updated to reflect the committed changes.
rnk added a comment.Aug 23 2021, 3:25 PM

Thanks, I think I patched it in and tested it but didn't push it.