SBProcess::Detach kills target

Hi,

Is this expected behavior or am I doing something wrong?

I am running my C++ program that uses LLDB API on Linux Ubuntu 15.10.

If I attach to already running process then SBProcess::Detach() behaves as expected - my debugger quits and the target keeps running. But if the target was launched by my debugger, then detach just kills it. Is there any way to leave the target running?

Thanks,
Eugene

Calling SBProcess::Detach() on a process that is currently running should always detach and this seems like a bug. This might be this way because if you launch a process in LLDB and then quit:

% lldb /bin/ls
(lldb) b malloc
(lldb) run
(lldb) quit

This should kill the process if it was launched and detach if we attached. But only when we quit without telling it to do something. If we did:

% lldb /bin/ls
(lldb) b malloc
(lldb) run
(lldb) detach

Then this should always detach if the user explicitly requests it no matter how it was launched.

I vaguely remember that not all Unixen support detaching from a process that is a child of the debugger that is attached to it. If you run the process under gdb & detach, does the process survive? This may not be an exact test, since gdb may use procfs rather than ptrace, I don't know any more... But if it doesn't work for gdb, it's probably a system limitation.

Anyway, launch then detach works as Greg described on OS X, so all the bits down to the call into the Process plugin's Detach is working correctly. So either there's a bug in llgs or in the Process plugin for Linux's detach.

Jim

There is no system restriction which prevents you from doing this.
(Without any investigation) my guess would be that your inferior is
dying of SIGHUP, which it receives when we close the master end of its
pty. Could you check whether the behavior persists if your app blocks
SIGHUP and/or you launch it with "process launch --no-stdio").

pl

I believe this is not SIGHUP on debugger exit. I am using my own C++ program that calls into LLDB API. So, this program is still alive after calling SBProcess::Detach() but the target dies. Also, the target intercepts SIGHUP to do cleanup before exiting. I put printf there, it was not hit.

I tried interactive LLDB, the target is not there:

Process 49145 stopped

  • thread #1: tid = 49145, …, stop reason = signal SIGSTOP
    frame #0: 0x00007ffff6a5bbed libc.so.6 at syscall-template.S:81
    (lldb) detach

Process 49145 detached

(lldb) q

eugene@EUGENEBI-L1:~/tmp$ ps

PID TTY TIME CMD

30714 pts/17 00:00:00 bash

49259 pts/17 00:00:00 ps

eugene@EUGENEBI-L1:~/tmp$

Eugene

So I have made a small test program (which does nothing but spin in a
loop), and indeed it is the SIGHUP that kills it after detach. If the
test program blocks the signal, then it continues running even after
detach:
$ cat a.c
#include <unistd.h>
#include <signal.h>

int main() {
    signal(SIGHUP, SIG_IGN);
    for (;:wink: sleep(1);
}
$ cc a.c -g
$ ps -A | grep a.out
$ ~/ll/build/dbg/bin/lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) b 6
Breakpoint 1: where = a.out`main + 19 at a.c:6, address = 0x0000000000400590
(lldb) r
Process 13416 launched: './a.out' (x86_64)
Process 13416 stopped
* thread #1: tid = 13416, 0x0000000000400590 a.out`main + 19 at a.c:6,
name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x0000000000400590 a.out`main + 19 at a.c:6
   3
   4 int main() {
   5 signal(SIGHUP, SIG_IGN);
-> 6 for (;:wink: sleep(1);
   7 }
(lldb) detach
Process 13416 detached
(lldb) q
$ ps -A | grep a.out
13416 ? 00:00:00 a.out

I believe this is not SIGHUP on debugger exit. I am using my own C++ program
that calls into LLDB API. So, this program is still alive after calling
SBProcess::Detach() but the target dies. Also, the target intercepts SIGHUP
to do cleanup before exiting. I put printf there, it was not hit.

The fact whether your program is alive irrelevant. What matters is
that by cleaning up the process structure, we will also close the
master end of the pty used for inferior communication, and this is
what causes the SIGHUP. For that reason you also cannot use a printf
to do diagnostics as the output has nowhere to go. Note that lldb's
behavior here will be different from gdb as gdb does not do stdio
redirection, and has the inferior share the pty with the debugger (in
which case your program will die when you close the terminal window).

I tried interactive LLDB, the target is not there:

Process 49145 stopped
* thread #1: tid = 49145, ..., stop reason = signal SIGSTOP
    frame #0: 0x00007ffff6a5bbed libc.so.6 at syscall-template.S:81
(lldb) detach
Process 49145 detached
(lldb) q
eugene@EUGENEBI-L1:~/tmp$ ps
  PID TTY TIME CMD
30714 pts/17 00:00:00 bash
49259 pts/17 00:00:00 ps

Note that the inferior will not show up here even if it exists, as ps
will only list the processes with the same tty, but at this point the
inferior process has no tty.

Good luck with your investigations.

pl

Right, my bad. The problem was that when debugger detaches the stdio does not go anywhere so I failed to see my printf.

Still, is this how it is supposed to be? I naively assume that if we don’t send SIGHUP in attach scenario we should not send it in launch scenario too.

Thanks,
Eugene

Just a wild guess - is this SIGHUP because stdin/stdout are broken? I.e. the debugger closes its pty’s on detach and that causes the signal?
What is the behavior on MAC?

We are not sending the SIGHUP, it is automatically getting sent by the
OS when the master end of the pty gets closed. The reason you are not
seeing this in the attach scenario is that we do not intercept
inferior stdio in this case (it's not possible, or desirable, since
the process is already running). This is also the reason
SBProcess.GetSTDOUT does not return anything in the attach scenario. I
am not familiar with the details of the Mac implementation and I
cannot tell you why is this not happening there.
I guess one way to fix this would be to have a special mode of
starting the inferior without a controlling terminal, but I am not
sure if this would be a generally useful feature. What is it that you
are trying to do anyway?

pl

It might be also possible to run an expression that will route stdin/stdout/stderr to /dev/null before detaching if we know that we have a master/slave pty hooked up the the inferior's in/out/err. We could run an expression like:

int fd = open("/dev/null", O_RDWR);
close(0);
close(1);
close(2);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);

Then the program could continue normally? So this might need to be part of detach code, but it should only be done if we used a pty.

One other thing to try is to write a 0x04 to the master side of the pty. Since the master/slave is emulating a terminal, this is how you shut it down as if you just close the master side, and if the other process is doing a fgets(...) from the slave side, it won't cause the slave to exit, but writing the EOF (0x04) byte to the master side _will_ cause the fgets(...) to exit on the other side.

Greg

OK, I got the picture, thanks a lot!

What is it that you are trying to do anyway?

Well, target termination during detach is unexpected, so my customers might get confused. Fortunately I am in control of the target program too, so I’ll just ignore SIGHUP for the time being.

Thanks,
Eugene

It might be also possible to run an expression that will route stdin/stdout/stderr to /dev/null before detaching if we know that we have a master/slave pty hooked up the the inferior's in/out/err. We could run an expression like:

(At least on linux) you would also need something like:
ioctl(open("/dev/tty", O_RDWR), TIOCNOTTY)
without it, the process will remain tied to the pty and will get a
HUP. Then redirection of file descriptors becomes optional: The
program will not get a SIGHUP, although it will get a SIGPIPE if it
tries to write some output to the slave end of the pty.

OK, I got the picture, thanks a lot!

     > What is it that you are trying to do anyway?

Well, target termination during detach is unexpected, so my customers might
get confused.

In case of a console debugger, I don't think anybody would even try
detaching from a launched program. For a graphical debugger, yes, it
will be confusing. In case you don't need access to inferior stdio
running with "process launch --no-stdio" might be an option. Right
now, it redirects io to /dev/null, but it still sets up a controlling
pty, which means you get the SIGHUP. However, I don't think a pty is
needed in this case and it sounds like it could be a good idea to
avoid creating it. Patches welcome.

pl