From patchwork Mon Feb 24 20:14:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom de Vries X-Patchwork-Id: 38293 Received: (qmail 70484 invoked by alias); 24 Feb 2020 20:14:10 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 70475 invoked by uid 89); 24 Feb 2020 20:14:10 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=003, control-c, controlc, Continuing X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 24 Feb 2020 20:14:08 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id E9725AF4E; Mon, 24 Feb 2020 20:14:05 +0000 (UTC) Date: Mon, 24 Feb 2020 21:14:04 +0100 From: Tom de Vries To: gdb-patches@sourceware.org Cc: Pedro Alves Subject: [PATCH][gdb] Fix hang after ext sigkill Message-ID: <20200224201403.GA7079@delia> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-IsSubscribed: yes Hi, Consider the test-case from this patch, compiled with pthread support: ... $ gcc src/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.c -lpthread ... After running, the program sleeps: ... $ gdb a.out Reading symbols from a.out... (gdb) r 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 0x7ffff77fe700 (LWP 22604)] ... Until we interrupt it with a control-C: ... ^C Thread 1 "a.out" received signal SIGINT, Interrupt. 0x00007ffff78c50f0 in nanosleep () from /lib64/libc.so.6 (gdb) ... If we then kill the inferior using an external SIGKILL: ... (gdb) shell killall -s SIGKILL a.out ... 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 which repeating the same warning. Typing control-C no longer helps, and we have to kill gdb using kill. 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. OK for trunk? Thanks, - Tom [gdb] Fix hang after ext sigkill gdb/ChangeLog: 2020-02-24 Tom de Vries PR gdb/25471 * thread.c (scoped_restore_current_thread::scoped_restore_current_thread): Catch exception in get_frame_id. (scoped_restore_current_thread::~scoped_restore_current_thread): Handle lack of inferior. gdb/testsuite/ChangeLog: 2020-02-24 Tom de Vries PR gdb/25471 * gdb.threads/hang-after-ext-sigkill.c: New test. * gdb.threads/hang-after-ext-sigkill.exp: New file. * lib/gdb.exp (runto): Handle "Temporary breakpoint" string. --- gdb/testsuite/gdb.threads/hang-after-ext-sigkill.c | 40 ++++++++++++ .../gdb.threads/hang-after-ext-sigkill.exp | 73 ++++++++++++++++++++++ gdb/testsuite/lib/gdb.exp | 2 +- gdb/thread.c | 14 ++++- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.c b/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.c new file mode 100644 index 0000000000..bfce6c3085 --- /dev/null +++ b/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.c @@ -0,0 +1,40 @@ +/* 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 + +static void * +fun (void *dummy) +{ + while (1) + sleep (1); + + return NULL; +} + +int +main (void) +{ + pthread_t thread; + pthread_create (&thread, NULL, fun, NULL); + + while (1) + sleep (1); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.exp b/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.exp new file mode 100644 index 0000000000..3702eb8c13 --- /dev/null +++ b/gdb/testsuite/gdb.threads/hang-after-ext-sigkill.exp @@ -0,0 +1,73 @@ +# 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 . + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + {pthreads}] == -1} { + return -1 +} + +set res [runto main no-message temporary] +if { $res != 1 } { + return -1 +} + +set pid -1 +gdb_test_multiple "info inferior 1" "get inferior pid" { + -re -wrap "process (\[0-9\]*).*" { + set pid $expect_out(1,string) + pass $gdb_test_name + } +} +if { $pid == -1 } { + return -1 +} + +gdb_test_multiple "continue" "" { + -re "Continuing" { + pass $gdb_test_name + } +} + +send_gdb "\003" + +gdb_test_multiple "" "get sigint" { + -re -wrap "Thread \[0-9\]+ .* received signal SIGINT, Interrupt\..*" { + pass $gdb_test_name + } +} + +gdb_test_no_output "shell kill -s SIGKILL $pid" "shell kill -s SIGKILL pid" + +# Expect the signal to arrive, and the program to terminate. +# Ideally at the first continue, currently though at the second. +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\." +set msg [join [list $killed_msg $no_longer_exists_msg $not_being_run_msg] \ + ".*"] + +# Don't expect '$gdb_prompt $', there still may be output after the prompt, +# f.i.: +# ... +# (gdb) [Thread 0x7ffff74c6700 (LWP 19277) exited]^M +# ... +gdb_test_multiple "continue" "" { + -re ".*\r\n$gdb_prompt " { + gdb_test "continue" $msg $gdb_test_name + } +} + diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 81518b9646..745694df2d 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -571,7 +571,7 @@ proc runto { function args } { } return 1 } - -re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { + -re "\[Bb\]reakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { if { $print_pass } { pass $test_name } diff --git a/gdb/thread.c b/gdb/thread.c index 54b59e2244..9876ca3c76 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1444,6 +1444,8 @@ scoped_restore_current_thread::restore () scoped_restore_current_thread::~scoped_restore_current_thread () { + if (m_inf == NULL) + return; if (!m_dont_restore) { try @@ -1488,7 +1490,17 @@ scoped_restore_current_thread::scoped_restore_current_thread () else frame = NULL; - m_selected_frame_id = get_frame_id (frame); + try + { + m_selected_frame_id = get_frame_id (frame); + } + catch (const gdb_exception &ex) + { + m_inf = NULL; + m_selected_frame_id = null_frame_id; + m_selected_frame_level = -1; + return; + } m_selected_frame_level = frame_relative_level (frame); tp->incref ();