You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LLVM currently assumes that if a function preserves the value of a register, this register can be safely accessed from a landing pad even if the function unwinds.
f() is marked as ms_abi, where rdi is callee-saved, so the value of arg can be read out from rdi after invoking f(). That's what LLVM does both if f() returns and in test's cleanup pad.
Unfortunately, that's incorrect behavior. According to the Itanium C++ ABI, the landing pad can only rely on the registers that are callee-saved by the base ABI. For Linux, "base ABI" is the SysV ABI, where rdi is caller-saved, so the unwinding library is not required to restore rdi.
While LLVM's libunwind goes beyond the EH ABI requirements and restores rdi, libgcc indeed doesn't (which I'd argue is compliant with the standard). When compiled against libgcc, the above code produces Dropper{random garbage} instead of Dropper{1}.
I've tested this on clang 18.1.8 from the Arch repos, built against libgcc. It compiles the test function from above to
LLVM currently assumes that if a function preserves the value of a register, this register can be safely accessed from a landing pad even if the function unwinds.
For example (x86_64):
f()
is marked asms_abi
, whererdi
is callee-saved, so the value ofarg
can be read out fromrdi
after invokingf()
. That's what LLVM does both iff()
returns and intest
's cleanup pad.Unfortunately, that's incorrect behavior. According to the Itanium C++ ABI, the landing pad can only rely on the registers that are callee-saved by the base ABI. For Linux, "base ABI" is the SysV ABI, where
rdi
is caller-saved, so the unwinding library is not required to restorerdi
.While LLVM's libunwind goes beyond the EH ABI requirements and restores
rdi
, libgcc indeed doesn't (which I'd argue is compliant with the standard). When compiled against libgcc, the above code producesDropper{random garbage}
instead ofDropper{1}
.I've tested this on clang 18.1.8 from the Arch repos, built against libgcc. It compiles the
test
function from above towhich erroneously assumes
rsi
is retained rather thanrdi
, but it's the same bug anyway.The text was updated successfully, but these errors were encountered: