Re: GDB (not) handling SIGINT...?

Pedro Alves <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
On 11/14/2018 10:32 PM, Simon Marchi wrote:
> On 2018-11-13 17:37, Paul Smith wrote:
>> Hi all; I'm using GDB 8.1 on a modern 64bit GNU/Linux system (Ubuntu
>> 18.04LTS).
>>
>> Recently I added a call to sigtimedwait() for SIGINT into my
>> (multithreaded) program and now I'm having an issue with GDB.
>>
>> What I want is that if I attach to my program then continue, then use
>> ^C at the GDB terminal, I should get a (gdb) prompt back but I do NOT
>> want the SIGINT delivered to my program to wake up my sigtimedwait()
>> call (because it will cause my program to do various things that I
>> don't want it to do).
>>
>> I see that SIGINT is set to nopass:
>>
>>   (gdb) info signals SIGINT
>>   Signal        Stop      Print   Pass to program Description
>>   SIGINT        Yes       Yes     No              Interrupt
>>
>> but yet when I use ^C at the GDB prompt my sigtimedwait() call inside
>> my program does return with "2" (SIGINT), which I don't want.
>>
>> I guess I don't understand what the docs mean when they say that the
>> signal is not passed to the process under debug.  Note that in my case
>> I'm attaching to the program from a completely different terminal so
>> there's no issue with process groups etc. and as far as I can
>> understand it, the signal should only be delivered to GDB not my
>> process, so unless there's some weird magic at work here it must be GDB
>> forwarding that signal to my process.
>>
>> Anyone have any thoughts about this?
>>
>> Cheers!
> 
> I was able to reproduce it with, it really sounds like a bug.
> 
> If others want to try, here's my test program:
> 
> #include <stdio.h>
> #include <signal.h>
> #include <stdlib.h>
> 
> int main()
> {
>     sigset_t set;
>     sigemptyset(&set);
>     sigaddset(&set, SIGINT);
>     sigprocmask(SIG_BLOCK, &set, NULL);
>     for (int i = 0; i < 10; i++) {
>         int n = sigwaitinfo(&set, NULL);
>         printf("signal %d\n", n);
>     }
> }
> 
> 
> Run in a terminal, attach with GDB in another terminal, continue, then ctrl-C in GDB's terminal.  The first call to sigwaitinfo returns -1, I think it's expected as the syscall gets interrupted.  But the subsequent calls return 2, showing that indeed the process has received a SIGINT.
> 
> Paul, could you please file a bug?  You can re-use this test program if you want.

There are a few things going on here, none of it is really new, though:

#1 - If your program blocks SIGINT and then uses sigwait, then GDB won't
     ever intercept the SIGINT, because ptrace doesn't ever see the signal.
     This is an ancient issue.  See:
       https://sourceware.org/bugzilla/show_bug.cgi?id=9425

#2 - If you attach to a process instead of running it from GDB, then ctrl-c
     reaches gdb first, and then GDB sends/forwards a SIGINT to the child process.
     Normally this then causes ptrace to intercept the SIGINT, but, see #1 above.
     This case ("attach"), could be handled by GDB instead stopping the
     process with SIGTOP or even better, PTRACE_INTERRUPT.  Note, TBC, would
     only work with attach/a separate terminal.

#3 - If you run the process instead of attaching, in the same terminal
     as GDB, then ctrl-c reaches the inferior process first (because
     the inferior is put in the foreground), gdb would have no chance to
     do PTRACE_INTERRUPT at all.  That would be fixable (combined with 
     PTRACE_INTERRUPT) by my WIP branch here:
       https://github.com/palves/gdb/commits/palves/tty-always-separate-session
     which effectively makes the "run" case the same as the "attach" case,
     by always putting the inferior in a separate terminal session.

Thanks,
Pedro Alves
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.