From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2205) id B6063384B0C1; Tue, 21 Apr 2020 13:46:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B6063384B0C1 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Tom de Vries To: gdb-cvs@sourceware.org Subject: [binutils-gdb] [gdb] Fix hang after ext sigkill X-Act-Checkin: binutils-gdb X-Git-Author: Tom de Vries X-Git-Refname: refs/heads/master X-Git-Oldrev: 946422b6a113063b9bbd72832ed13d4694134597 X-Git-Newrev: 4778a5f87d253399083565b4919816f541ebe414 Message-Id: <20200421134600.B6063384B0C1@sourceware.org> Date: Tue, 21 Apr 2020 13:46:00 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Apr 2020 13:46:00 -0000 https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4778a5f87d253399083565b4919816f541ebe414 commit 4778a5f87d253399083565b4919816f541ebe414 Author: Tom de Vries Date: Tue Apr 21 15:45:57 2020 +0200 [gdb] Fix hang after ext sigkill Consider the test-case from this patch, compiled with pthread support: ... $ gcc gdb/testsuite/gdb.threads/killed-outside.c -lpthread -g ... After running to all_started, we can print pid: ... $ gdb a.out -ex "b all_started" -ex run -ex "delete 1" -ex "p pid" ... Reading symbols from a.out... Breakpoint 1 at 0x40072b: file killed-outside.c, line 29. Starting program: /data/gdb_versions/devel/a.out [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". [New Thread 0x7ffff77fc700 (LWP 3155)] Thread 1 "a.out" hit Breakpoint 1, all_started () at killed-outside.c:29 29 } $1 = 3151 (gdb) ... If we then kill the inferior using an external SIGKILL: ... (gdb) shell kill -9 3151 ... and subsequently continue: ... (gdb) c Continuing. Couldn't get registers: No such process. Couldn't get registers: No such process. (gdb) Couldn't get registers: No such process. (gdb) Couldn't get registers: No such process. (gdb) Couldn't get registers: No such process. ... gdb hangs repeating the same warning. Typing control-C no longer helps, and we have to kill gdb. This is a regression since commit 873657b9e8 "Preserve selected thread in all-stop w/ background execution". The commit adds a scoped_restore_current_thread typed variable restore_thread to fetch_inferior_event, and the hang is caused by the constructor throwing an exception. Fix this by catching the exception in the constructor. Build and reg-tested on x86_64-linux. gdb/ChangeLog: 2020-04-21 Tom de Vries PR gdb/25471 * thread.c (scoped_restore_current_thread::scoped_restore_current_thread): Catch exception in get_frame_id. gdb/testsuite/ChangeLog: 2020-04-21 Tom de Vries PR gdb/25471 * gdb.threads/killed-outside.c: New test. * gdb.threads/killed-outside.exp: New file. Diff: --- gdb/ChangeLog | 7 +++ gdb/testsuite/ChangeLog | 6 +++ gdb/testsuite/gdb.threads/killed-outside.c | 64 ++++++++++++++++++++++++++++ gdb/testsuite/gdb.threads/killed-outside.exp | 57 +++++++++++++++++++++++++ gdb/thread.c | 12 +++++- 5 files changed, 144 insertions(+), 2 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index aa99da0c4d9..0e80cdb2d16 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2020-04-21 Tom de Vries + + PR gdb/25471 + * thread.c + (scoped_restore_current_thread::scoped_restore_current_thread): Catch + exception in get_frame_id. + 2020-04-20 Tom Tromey * python/python.c (struct gdbpy_event): Mark move constructor as diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index eee1fa375a8..f72256730f3 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-04-21 Tom de Vries + + PR gdb/25471 + * gdb.threads/killed-outside.c: New test. + * gdb.threads/killed-outside.exp: New file. + 2020-04-20 Gary Benson * gdb.base/nested-subp1.exp: Use support_nested_function_tests. diff --git a/gdb/testsuite/gdb.threads/killed-outside.c b/gdb/testsuite/gdb.threads/killed-outside.c new file mode 100644 index 00000000000..ac4cf0b07aa --- /dev/null +++ b/gdb/testsuite/gdb.threads/killed-outside.c @@ -0,0 +1,64 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include + +pid_t pid; + +static pthread_barrier_t threads_started_barrier; + +static void +all_started (void) +{ +} + +static void * +fun (void *dummy) +{ + int i; + + pthread_barrier_wait (&threads_started_barrier); + + for (i = 0; i < 180; i++) + sleep (1); + + pthread_exit (NULL); +} + +int +main (void) +{ + int i; + pthread_t thread; + + pid = getpid (); + + pthread_barrier_init (&threads_started_barrier, NULL, 2); + + pthread_create (&thread, NULL, fun, NULL); + + pthread_barrier_wait (&threads_started_barrier); + + all_started (); + + for (i = 0; i < 180; i++) + sleep (1); + + exit (EXIT_SUCCESS); +} diff --git a/gdb/testsuite/gdb.threads/killed-outside.exp b/gdb/testsuite/gdb.threads/killed-outside.exp new file mode 100644 index 00000000000..ff5a1157285 --- /dev/null +++ b/gdb/testsuite/gdb.threads/killed-outside.exp @@ -0,0 +1,57 @@ +# Copyright (C) 2020 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This test-case tests that continuing an inferior that has been killed +# using an external sigkill does not make gdb misbehave. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + {pthreads debug}] == -1} { + return -1 +} + +if { ![runto "all_started"] } { + return -1 +} +delete_breakpoints + +set testpid [get_valueof "" "pid" -1 "get pid of inferior"] +if { $testpid == -1 } { + return -1 +} +remote_exec target "kill -9 ${testpid}" + +# Give it some time to die. +sleep 2 + +set no_such_process_msg "Couldn't get registers: No such process\." +set killed_msg "Program terminated with signal SIGKILL, Killed\." +set no_longer_exists_msg "The program no longer exists\." +set not_being_run_msg "The program is not being run\." + +gdb_test_multiple "continue" "prompt after first continue" { + -re "Continuing\.\r\n$no_such_process_msg\r\n$no_such_process_msg\r\n$gdb_prompt " { + pass $gdb_test_name + # Two times $no_such_process_msg. The bug condition was triggered, go + # check for it. + gdb_test_multiple "" "messages" { + -re ".*$killed_msg.*$no_longer_exists_msg\r\n" { + pass $gdb_test_name + gdb_test "continue" $not_being_run_msg "second continue" + } + } + } +} diff --git a/gdb/thread.c b/gdb/thread.c index c6e3d356a5a..03805bd2565 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1488,8 +1488,16 @@ scoped_restore_current_thread::scoped_restore_current_thread () else frame = NULL; - m_selected_frame_id = get_frame_id (frame); - m_selected_frame_level = frame_relative_level (frame); + try + { + m_selected_frame_id = get_frame_id (frame); + m_selected_frame_level = frame_relative_level (frame); + } + catch (const gdb_exception_error &ex) + { + m_selected_frame_id = null_frame_id; + m_selected_frame_level = -1; + } tp->incref (); m_thread = tp;