Mac does not allow clearing sigaltstack after abnormal signal exit
If we have a crash in a signal handler and we then exit DR we get this on Mac:
<Application /Users/cutler/derek/dr/git/build_x86_dbg_tests/suite/tests/bin/linux.signal0000 (66119). Internal Error: DynamoRIO debug check failure: /Users/cutler/derek/dr/git/src/core/unix/signal.c:1199 i == 0
The sigaltstack return val is -22=EINVAL, ss_sp is 0, ss_flags is SS_DISABLE
Xref
/* Although "man sigaltstack" claims ss_sp and ss_size are ignored when
* SS_DISABLE is set, on Mac we get ENOMEM if we clear ss_sp beforehand.
*/
That's from the size check at the end here, which is after the EINVAL checks:
/extsw/mac/xnu-2422.1.72/bsd/kern/kern_sig.c
if (ss.ss_size < OLDMINSIGSTKSZ)
return (ENOMEM);
Or is it? It should return earlier for SS_DISABLE. This is in DrMem's tests/signal.c -- may want to revisit that. And I did: and confirmed I get ENOMEM if ss_size is 0 when flags==SS_DISABLE.
Anyway, we're getting EINVAL. The man page says:
Trying to disable an active stack will cause sigaltstack to return -1 with errno
set to EINVAL.
But we are not currently on the stack:
removing our signal stack 0x4f069000 - 0x4f077000
XXX sigaltstack=>-22 for 0x4f069000 0xe000 0x4 cur=0x4f04eb80
The app crash is inside the handler: does the kernel really track whether we called sigreturn? It looks like it does:
/extsw/mac/xnu-2422.1.72/bsd/kern/kern_sig.c
if (ss.ss_flags & SA_DISABLE) {
/* if we are here we are not in the signal handler ;so no need to check */
if (uth->uu_sigstk.ss_flags & SA_ONSTACK)
return (EINVAL);
/extsw/mac/xnu-2422.1.72/bsd/dev/i386/unix_signal.c
sendsig()
ut->uu_sigstk.ss_flags |= SA_ONSTACK;
sigreturn()
ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
This doesn't seem like the right thing for the kernel to do, but we'll have to work around it by allowing the syscall to fail.