diff options
author | Pedro Alves <palves@redhat.com> | 2016-06-21 01:11:57 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2016-06-21 01:11:57 +0100 |
commit | 49940788ab38b9d58c663cf38855f29c0ebb1b55 (patch) | |
tree | ef322e16fd2feb6219aacba550aac37b9b38772f /gdb/fork-child.c | |
parent | ef274d26b57336b3baa5bb0ae93b49178bc45631 (diff) | |
download | gdb-49940788ab38b9d58c663cf38855f29c0ebb1b55.zip gdb-49940788ab38b9d58c663cf38855f29c0ebb1b55.tar.gz gdb-49940788ab38b9d58c663cf38855f29c0ebb1b55.tar.bz2 |
Always switch fork child to the main UI
The following scenario:
- gdb started in normal CLI mode.
- separate MI channel created with new-ui
- inferior output redirected with the "set inferior-tty" command.
- use -exec-run in the MI channel to run the inferior
is presently mishandled.
When we create the inferior, in fork-child.c, right after vfork, we'll
close all the file descriptors in the vfork child, and then dup the
tty to file descriptors 0/1/2, create a session, etc. Note that when
we close all descriptors, we close the file descriptors behind
gdb_stdin/gdb_stdout/gdb_stderr of all secondary UIs... So if
anything goes wrong in the child and it calls warning/error, it'll end
up writting to the current UI's stdout/stderr streams, which are
backed by file descriptors that have since been closed. Because this
happens in a vfork region, the corresponding stdin/stdout/stderr in
the parent/gdb end up corrupted.
The fix is to switch to the main UI right after the vfork, so that
gdb_stdin/gdb_stdout/gdb_stderr are correctly mapped to
stdin/stdout/stderr (and thus to file descriptors 0/1/2), so this code
works as it has always worked.
(Technically, we're doing a lot of stuff we shouldn't be doing after a
vfork, while we should only be calling async-signal-safe functions.)
gdb/ChangeLog:
2016-06-21 Pedro Alves <palves@redhat.com>
* fork-child.c (fork_inferior): Switch the child to the main UI
right after vfork. Save/restore the current UI in the parent.
Flush outputs of the main UI instead of the current UI.
gdb/testsuite/ChangeLog:
2016-06-21 Pedro Alves <palves@redhat.com>
* gdb.mi/mi-exec-run.exp: New file.
Diffstat (limited to 'gdb/fork-child.c')
-rw-r--r-- | gdb/fork-child.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/gdb/fork-child.c b/gdb/fork-child.c index 204b7cf..8ac3bef 100644 --- a/gdb/fork-child.c +++ b/gdb/fork-child.c @@ -31,6 +31,7 @@ #include "gdbcmd.h" #include "solib.h" #include "filestuff.h" +#include "top.h" #include <signal.h> @@ -141,6 +142,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env, struct inferior *inf; int i; int save_errno; + struct ui *save_ui; /* If no exec file handed to us, get it from the exec-file command -- with a good, common error message if none is specified. */ @@ -275,6 +277,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env, restore it. */ save_our_env = environ; + /* Likewise the current UI. */ + save_ui = current_ui; + /* Tell the terminal handling subsystem what tty we plan to run on; it will just record the information for later. */ new_tty_prefork (inferior_io_terminal); @@ -282,8 +287,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env, /* It is generally good practice to flush any possible pending stdio output prior to doing a fork, to avoid the possibility of both the parent and child flushing the same data after the fork. */ - gdb_flush (gdb_stdout); - gdb_flush (gdb_stderr); + gdb_flush (main_ui->m_gdb_stdout); + gdb_flush (main_ui->m_gdb_stderr); /* If there's any initialization of the target layers that must happen to prepare to handle the child we're about fork, do it @@ -312,6 +317,16 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env, if (pid == 0) { + /* Switch to the main UI, so that gdb_std{in/out/err} in the + child are mapped to std{in/out/err}. This makes it possible + to use fprintf_unfiltered/warning/error/etc. in the child + from here on. */ + current_ui = main_ui; + + /* Close all file descriptors except those that gdb inherited + (usually 0/1/2), so they don't leak to the inferior. Note + that this closes the file descriptors of all secondary + UIs. */ close_most_fds (); if (debug_fork) @@ -378,6 +393,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env, /* Restore our environment in case a vforked child clob'd it. */ environ = save_our_env; + /* Likewise the current UI. */ + current_ui = save_ui; + if (!have_inferiors ()) init_thread_list (); |