[PATCH 0/6] Fix unwinding through sigreturn trampolines

Szabolcs Nagy szabolcs.nagy at arm.com
Tue Jun 23 07:11:09 EDT 2020

The 06/23/2020 12:11, Ard Biesheuvel wrote:
> So the safest way to fix this (imho) is to add CFI directives that
> mirror what libunwind does unconditionally, and libgcc when it spots
> the mov/svc pair on unannotated addresses, which is to restore all the
> registers from the sigframe, and to use regs->pc as the return address
> (which is where the unwind should proceed, rather than at whatever
> value happened to reside in x30 at the point the signal was taken)
> The only hairy bit is the FP/SIMD registers, which are ignored by
> libunwind, and only half-restored by libgcc (which appears to assume
> that only d8..d15 need to be restored). This means throwing a C++
> exception in a signal handler and catching it outside of it is going
> to be difficult to get 100% correct, but this is something that
> appears to be broken already everywhere. (Unless there are some
> AAPCS/ABI rules that specify that FP/SIMD registers have to be assumed
> clobbered when catching an exception)

all fp/simd registers are assumed to be clobbered after
a function call, except for the bottom part of v8-v15
(sve calls preserve more: v8-v23 which may be a problem)

this means if the exception is caught at least one call
frame above the interrupted function then the libgcc
logic should work.

if you want to catch exceptions at the same call frame
that is interrupted by the signal, then you need to
compile with -fnon-call-exceptions which has limitations
anyway and not expected to be reliable (apparently on
aarch64 libgcc does not even support this usage with
respect to fp/simd regs, which is good to know..)

this is all fine because c++ does not define exception
handling across signal handlers.

as for thread cancellation in glibc: it uses exception
mechanism for cleanups, but the default cancel state
is PTHREAD_CANCEL_DEFERRED which means only blocking
libc calls throw (so -fexceptions is enough and the
libgcc logic is fine), if you switch to
PTHREAD_CANCEL_ASYNCHRONOUS then there may be a problem
but you can only do pure computations in that state,
(only 3 libc functions are defined to be async cancel
safe), i think you cannot register cleanup handlers
that run on the same stack frame that may be async

More information about the linux-arm-kernel mailing list