powerpc/183040: Nested signal handling is broken

Konstantin Belousov kostikbel at gmail.com
Thu Oct 17 07:32:04 UTC 2013


On Wed, Oct 16, 2013 at 07:49:13PM -0400, Julio Merino wrote:
> 
> >Number:         183040
> >Category:       powerpc
> >Synopsis:       Nested signal handling is broken
> >Confidential:   no
> >Severity:       serious
> >Priority:       medium
> >Responsible:    freebsd-ppc
> >State:          open
> >Quarter:        
> >Keywords:       
> >Date-Required:
> >Class:          sw-bug
> >Submitter-Id:   current-users
> >Arrival-Date:   Thu Oct 17 00:00:00 UTC 2013
> >Closed-Date:
> >Last-Modified:
> >Originator:     Julio Merino
> >Release:        FreeBSD 11.0-CURRENT powerpc
> >Organization:
> >Environment:
> System: FreeBSD mastodon.meroh.net 11.0-CURRENT FreeBSD 11.0-CURRENT #9 r256450M: Mon Oct 14 16:35:08 EDT 2013 jmmv at mastodon.meroh.net:/usr/obj/usr/src/sys/GENERIC64 powerpc
> 
> Also affects FreeBSD 10.0 alphas.
> 
> 	
> >Description:
> 	When programming a given signal twice in a nested manner, the
> 	unprogramming of the top-most signal handler does not properly
> 	restore the previous (non-default handler).  In other words:
> 
> 	program signal X
> 	  program signal X
> 	    deliver signal X to self -- custom handler runs
> 	  unprogram signal X
> 	  deliver signal X to self -- default handler runs or not delivered
> 	unprogram signal X
> 
> 	Interestingly, things seem to work well for X = SIGTERM but not
> 	for X = SIGHUP nor X = SIGINT.  I have not tested other signals.
> 
> 	I have encountered this bug while running the kyua test suite
> 	on a powerpc64 machine (specifics detailed above) and noticing
> 	a couple of tests fail, which work well in other operating
> 	systems and in amd64.  The test case below is derived form the
> 	code in kyua.
> 
> 	Here is the output of the test program on an amd64 machine,
> 	which to my knowledge is working properly:
> 
> SIGNAL 1
> Programming at level 1
> Programming at level 0
> Signal 1 caught correctly
> Unprogramming at level 0
> Signal 1 caught correctly
> Unprogramming at level 1
> 
> SIGNAL 2
> Programming at level 1
> Programming at level 0
> Signal 2 caught correctly
> Unprogramming at level 0
> Signal 2 caught correctly
> Unprogramming at level 1
> 
> SIGNAL 15
> Programming at level 1
> Programming at level 0
> Signal 15 caught correctly
> Unprogramming at level 0
> Signal 15 caught correctly
> Unprogramming at level 1
> 
> 	The same test program yields this on powerpc64:
> 
> SIGNAL 1
> Programming at level 1
> Programming at level 0
> Signal 1 caught correctly
> Unprogramming at level 0
> a.out: Signal 1 not caught
> 
> >How-To-Repeat:
> 	Build and run this test program:
> 
> -----
> #include <err.h>
> #include <signal.h>
> #include <stdbool.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> 
> static bool caught = false;
> 
> static void
> handler(const int signo)
> {
>     caught = true;
> }
> 
> static void
> do_it(const int signo, const int level)
> {
>     struct sigaction sa, old_sa;
> 
>     printf("Programming at level %d\n", level);
> 
>     sa.sa_handler = handler;
>     sigemptyset(&sa.sa_mask);
>     sa.sa_flags = SA_RESTART;
> 
>     if (sigaction(signo, &sa, &old_sa) == -1)
>         err(EXIT_FAILURE, "sigaction program failed");
> 
>     if (level > 0)
>         do_it(signo, level - 1);
> 
>     caught = false;
>     kill(getpid(), signo);
>     if (caught)
>         printf("Signal %d caught correctly\n", signo);
>     else
>         errx(EXIT_FAILURE, "Signal %d not caught\n", signo);
> 
>     if (sigaction(signo, &old_sa, NULL) == -1)
>         err(EXIT_FAILURE, "sigaction unprogram failed");
> 
>     printf("Unprogramming at level %d\n", level);
> }
> 
> static void
> try_one_signal(const int signo, const int level)
> {
>     printf("SIGNAL %d\n", signo);
>     do_it(signo, level);
>     printf("\n");
> }
> 
> int
> main(void)
> {
>     try_one_signal(SIGHUP, 1);
>     try_one_signal(SIGINT, 1);
>     try_one_signal(SIGTERM, 1);
>     return EXIT_SUCCESS;
> }

What you could do, is to localize the point where the breakage occur.
Add a function like this:

static void
print_sig_disposition(int signo)
{
	struct sigaction sa;
	sigaction(signo, NULL, &sa);
	printf("sig %d handler %p\n", signo, sa.sa_handler);
}

and sprinkle a calls to it often enough, to see where the reset of the
disposition happens.  Insert the call to the function into the signal
handler as well.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 834 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-ppc/attachments/20131017/97790986/attachment.sig>


More information about the freebsd-ppc mailing list