Skip to content

Commit 7180e04

Browse files
committed
Fix "attach" command vs user input race
On async targets, a synchronous attach is done like this: #1 - target_attach is called (PTRACE_ATTACH is issued) #2 - a continuation is installed #3 - we go back to the event loop #4 - target reports stop (SIGSTOP), event loop wakes up, and attach continuation is called #5 - among other things, the continuation calls target_terminal_inferior, which removes stdin from the event loop Note that in #3, GDB is still processing user input. If the user is fast enough, e.g., with something like: echo -e "attach PID\nset xxx=1" | gdb ... then the "set" command is processed before the attach completes. We get worse behavior even, if input is a tty and therefore readline/editing is enabled, with e.g.,: (gdb) attach PID\nset xxx=1 we then crash readline/gdb, with: Attaching to program: attach-wait-input, process 14537 readline: readline_callback_read_char() called with no handler! Aborted $ Fix this by calling target_terminal_inferior before #3 above. The test covers both scenarios by running with editing/readline forced to both on and off. gdb/ 2014-07-09 Pedro Alves <[email protected]> * infcmd.c (attach_command_post_wait): Don't call target_terminal_inferior here. (attach_command): Call it here instead. gdb/testsuite/ 2014-07-09 Pedro Alves <[email protected]> * gdb.base/attach-wait-input.exp: New file. * gdb.base/attach-wait-input.c: New file.
1 parent 9a9a760 commit 7180e04

File tree

5 files changed

+186
-3
lines changed

5 files changed

+186
-3
lines changed

gdb/ChangeLog

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2014-07-09 Pedro Alves <[email protected]>
2+
3+
* infcmd.c (attach_command_post_wait): Don't call
4+
target_terminal_inferior here.
5+
(attach_command): Call it here instead.
6+
17
2014-07-09 Andrew Burgess <[email protected]>
28

39
* ada-varobj.c (ada_varobj_ops): Fill in is_path_expr_parent

gdb/infcmd.c

+16-3
Original file line numberDiff line numberDiff line change
@@ -2380,9 +2380,6 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
23802380

23812381
post_create_inferior (&current_target, from_tty);
23822382

2383-
/* Install inferior's terminal modes. */
2384-
target_terminal_inferior ();
2385-
23862383
if (async_exec)
23872384
{
23882385
/* The user requested an `attach&', so be sure to leave threads
@@ -2498,6 +2495,22 @@ attach_command (char *args, int from_tty)
24982495
based on what modes we are starting it with. */
24992496
target_terminal_init ();
25002497

2498+
/* Install inferior's terminal modes. This may look like a no-op,
2499+
as we've just saved them above, however, this does more than
2500+
restore terminal settings:
2501+
2502+
- installs a SIGINT handler that forwards SIGINT to the inferior.
2503+
Otherwise a Ctrl-C pressed just while waiting for the initial
2504+
stop would end up as a spurious Quit.
2505+
2506+
- removes stdin from the event loop, which we need if attaching
2507+
in the foreground, otherwise on targets that report an initial
2508+
stop on attach (which are most) we'd process input/commands
2509+
while we're in the event loop waiting for that stop. That is,
2510+
before the attach continuation runs and the command is really
2511+
finished. */
2512+
target_terminal_inferior ();
2513+
25012514
/* Set up execution context to know that we should return from
25022515
wait_for_inferior as soon as the target reports a stop. */
25032516
init_wait_for_inferior ();

gdb/testsuite/ChangeLog

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2014-07-09 Pedro Alves <[email protected]>
2+
3+
* gdb.base/attach-wait-input.exp: New file.
4+
* gdb.base/attach-wait-input.c: New file.
5+
16
2014-07-09 Andrew Burgess <[email protected]>
27

38
* gdb.mi/var-cmd.c (do_nested_struct_union_tests): New function
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* This testcase is part of GDB, the GNU debugger.
2+
3+
Copyright 2014 Free Software Foundation, Inc.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
17+
18+
#include <sys/types.h>
19+
#include <unistd.h>
20+
21+
volatile int should_exit = 0;
22+
int mypid;
23+
24+
static void
25+
setup_done (void)
26+
{
27+
}
28+
29+
int
30+
main (void)
31+
{
32+
unsigned int counter = 1;
33+
34+
mypid = getpid ();
35+
setup_done ();
36+
37+
for (counter = 0; !should_exit && counter < 100; counter++)
38+
sleep (1);
39+
return 0;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright 2014 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>. */
15+
16+
# Verify that GDB waits for the "attach" command to finish before
17+
# processing the following command.
18+
#
19+
# GDB used to have a race where on async targets, in the small window
20+
# between the attach request and the initial stop for the attach, GDB
21+
# was still processing user input.
22+
#
23+
# The issue was originally detected with:
24+
#
25+
# echo -e "attach PID\nset xxx=1" | gdb
26+
#
27+
# In that scenario, stdin is not a tty, which disables readline.
28+
# Explicitly turning off editing exercises the same code path, and is
29+
# simpler to do, so we test with both editing on and off.
30+
31+
# The test uses the "attach" command.
32+
if [target_info exists use_gdb_stub] {
33+
return
34+
}
35+
36+
standard_testfile
37+
38+
if {[build_executable "failed to build" $testfile $srcfile debug]} {
39+
return -1
40+
}
41+
42+
# Start the program running, and return its PID, ready for attaching.
43+
44+
proc start_program {binfile} {
45+
global gdb_prompt
46+
global decimal
47+
48+
clean_restart $binfile
49+
50+
if ![runto setup_done] then {
51+
fail "Can't run to setup_done"
52+
return 0
53+
}
54+
55+
# Get the PID of the test process.
56+
set testpid ""
57+
set test "get inferior process ID"
58+
gdb_test_multiple "p mypid" $test {
59+
-re " = ($decimal)\r\n$gdb_prompt $" {
60+
set testpid $expect_out(1,string)
61+
pass $test
62+
}
63+
}
64+
65+
gdb_test "detach" "Detaching from program: .*"
66+
67+
if {$testpid == ""} {
68+
return
69+
}
70+
71+
return $testpid
72+
}
73+
74+
# Do test proper. EDITING indicates whether "set editing" is on or
75+
# off.
76+
77+
proc test { editing } {
78+
global gdb_prompt
79+
global binfile
80+
global decimal
81+
82+
with_test_prefix "editing $editing" {
83+
84+
set testpid [start_program $binfile]
85+
if {$testpid == ""} {
86+
return
87+
}
88+
89+
# Enable/disable readline.
90+
gdb_test_no_output "set editing $editing"
91+
92+
# Send both commands at once.
93+
send_gdb "attach $testpid\nprint should_exit = 1\n"
94+
95+
# Use gdb_expect directly instead of gdb_test_multiple to
96+
# avoid races with the double prompt.
97+
set test "attach and print"
98+
gdb_expect {
99+
-re "Attaching to program.*process $testpid\r\n.*$gdb_prompt.*$decimal = 1\r\n$gdb_prompt $" {
100+
pass "$test"
101+
}
102+
timeout {
103+
fail "$test (timeout)"
104+
}
105+
}
106+
107+
# As we've used attach, on quit, we'll detach from the
108+
# program. Explicitly kill it in case we failed above.
109+
gdb_test "kill" \
110+
"" \
111+
"after attach, exit" \
112+
"Kill the program being debugged.*y or n. $" \
113+
"y"
114+
}
115+
}
116+
117+
foreach editing {"on" "off"} {
118+
test $editing
119+
}

0 commit comments

Comments
 (0)