raise() marked __leaf__ is not C-compliant?

Tadeus Prastowo 0x66726565@gmail.com
Wed Oct 28 19:23:17 GMT 2020


On Wed, Oct 28, 2020 at 6:34 PM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> On 28/10/2020 10:19, Tadeus Prastowo wrote:
> > On Wed, Oct 28, 2020 at 12:53 PM Adhemerval Zanella
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >> The sentence "raise() definitely runs a signal handler" is not really
> >> valid in a portable sense. Afaik neither C nor POSIX states which signals
> >> should be delivered synchronously or asynchronously (although some do
> >> only make sense to be delivered synchronously such as SIGSEGV).
> >>
> >> However, Linux does ran some signals synchronously and I agree that using
> >> leaf attribute is incorrect and lead to this kind of problems. My point is
> >> to be fully portable, you need to assume any signal might be delivered
> >> asynchronously (and C standard specifies the volatile sig_atomic_t for
> >> such cases).
> >
> > Thank you for your response.
> >
> > However, C, including C99, C11, and the latest C18 [1], says: "If a
> > signal handler is called, the raise function shall not return until
> > after the signal handler does."  And, POSIX [2] says: "If a signal
> > handler is called, the raise() function shall not return until after
> > the signal handler does."  So, the sentence "raise() definitely runs a
> > signal handler" is valid in a portable sense as required by the
> > standards, no?
>
> My understanding is it allows synchronous signals, not enforce it;
> and if the signal is synchronous then it should complete prior hand.

I understand your point as the C standard says:

[...] distinct values that are the signal numbers, each corresponding
to the specified condition:
SIGABRT [...]
SIGFPE [...]
SIGILL [...]
SIGINT [...]
SIGSEGV [...]
SIGTERM [...]
An implementation need not generate any of these signals, except as a
result of explicit calls to the raise function.  [...]  The complete
set of signals, their semantics, and their default handling is
implementation-defined; all signal numbers shall be positive.

[...]

void (*signal(int sig, void (*func)(int)))(int);
Description
[...]
When a signal occurs and func points to a function, it is
implementation-defined whether the equivalent of signal(sig, SIG_DFL);
is executed [...]; in the case of SIGILL, the implementation may
alternatively define that no action is taken.  Then the equivalent of
(*func)(sig); is executed.

End quote.

So, yes, you are right that the sentence "raise() definitely runs a
signal handler" is inaccurate because, as quoted above, C standard
allows an implementation to not run the handler that the user has
designated to handle the signal being generated by raise().  However,
if the implementation decides that "the equivalent of (*func)(sig); is
executed", then the C standard requires that "the raise function shall
not return until after the signal handler does."

To conclude, in my earlier post, I meant to say: Glibc-2.30 raise()
may run a signal handler that is defined in the current compilation
unit to use static variables.  So, unless the C standard says that it
is an undefined behavior to access a non-volatile object with static
storage duration from within a signal handler that is called
synchronously by raise() on a normal execution path, the marking of
raise() with __leaf__ makes raise() non-compliant with the C standard.

> > [1] Page 195 of
> > https://web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
> > [2] The raise section of Chapter 3 "System Interfaces" of IEEE
> > Standard for Information Technology---POSIX, Volume 2 "System
> > Interfaces", Issue 7.

Thank you for your patience in allowing me to make myself clear.

-- 
Best regards,
Tadeus


More information about the Libc-help mailing list