[PATCH v2 1/2] setjmp: Use BSD sematic as default for setjmp

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Mon Aug 7 18:33:39 GMT 2023



On 07/08/23 10:40, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
> 
>> On 07/08/23 09:54, Florian Weimer wrote:
>>> * Adhemerval Zanella Netto:
>>>
>>>> On 04/08/23 05:43, Florian Weimer wrote:
>>>>> * Adhemerval Zanella:
>>>>>
>>>>>> POSIX relaxed the relation of setjmp/longjmp and the signal mask
>>>>>> save/restore, meaning that setjmp does not require to be routed to
>>>>>> _setjmp to be standard compliant.
>>>>>>
>>>>>> This is done to avoid breakage of SIGABRT handlers, since to fully
>>>>>> make abort AS-safe, it is required to remove the recurisve lock
>>>>>> used to unblock SIGABRT prior raised the signal.
>>>>>>
>>>>>> Also, it allows caller to actually use setjmp, since from
>>>>>> 7011c2622fe3e10a29dbe74f06aaebd07710127d the symbol is unconditionally
>>>>>> routed to _setjmp.
>>>>>
>>>>> I still think we shouldn't do this due to the performance implications.
>>>>
>>>> By not changing it and with the abort AS-safe fix, the following code
>>>> will always abort the program:
>>>>
>>>> --
>>>>  static jmp_buf jb;
>>>>
>>>>  static void
>>>>  sigabrt_handler (int sig)
>>>>  {
>>>>    longjmp (jb, 1);
>>>>  }
>>>>
>>>>  struct sigaction sa = { .sa_handler = sigabrt_handler, .sa_flags = 0 };
>>>>  sigemptyset (&sa.sa_mask);
>>>>  assert (sigaction (SIGABRT, &sa, 0) == 0);
>>>>
>>>>  if (setjmp (jb) == 0)
>>>>    abort ();
>>>>
>>>>  if (setjmp (jb) == 0)
>>>>    abort ();
>>>>
>>>>  // No reached.
>>>> --
>>>>
>>>> Callers will need to change to sigsetjmp (..., 1) to have the same semantic.
>>>> That's the main reason I am suggesting this patch.
>>>
>>> Could we just unconditionally unblock SIGABRT at the start of abort,
>>> before the raise (SIGABRT) call?  Other signal handlers could still
>>> observe this, but I think this change isn't really part of the core
>>> async signal safety fix.
>>
>> My understanding is this still subject to same race condition with fork
>> and posix_spawn signal handling setup, and that's why I have removed it.
> 
> Concurrent fork from another thread does not matter here because that
> copies the signal mask from the fork-calling thread, not the
> abort-calling thread.  Does this address your concern?
> 
> I think the only gap is another signal being delivered to the
> abort-calling thread, and there the unblocking is sort-of implied by
> current POSIX anyway, so it's arguably to be observably.

I still think unblocking the signal on raise is not fully correct, since
calling abort in the SIGABRT handler itself leads to a recursive call
to the handler, which will eventually lead to a stack overflow.

By not messing with the signal handler, the process will be correctly
terminated as by receiving a SIGABRT.


More information about the Libc-alpha mailing list