From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1389 invoked by alias); 7 Feb 2012 19:14:12 -0000 Received: (qmail 1378 invoked by uid 22791); 7 Feb 2012 19:14:11 -0000 X-SWARE-Spam-Status: No, hits=-7.0 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 07 Feb 2012 19:13:56 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q17JDuQN016827 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 7 Feb 2012 14:13:56 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q17JDt0q008227; Tue, 7 Feb 2012 14:13:56 -0500 Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id q17JDsl9010964; Tue, 7 Feb 2012 14:13:54 -0500 From: Tom Tromey To: gdb-patches@sourceware.org Subject: RFC: fix crash when inferior exits during "continue" Date: Tue, 07 Feb 2012 19:14:00 -0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-02/txt/msg00083.txt.bz2 I'd appreciate comments on this patch. This patch fixes PR 13653. The bug is that you can make gdb crash with a certain sequence: set detach-on-fork off set target-async on set non-stop on ... run inferior, which forks; then the child stops somewhere inferior 2 continue ... inferior 2 exits, gdb crashes The crash happens because do_restore_current_thread_cleanup tries to select a deleted inferior, causing the assertion in set_current_inferior to fail. This patch fixes the problem by noticing that the saved inferior no longer exists, and arbitrarily selecting some other inferior instead. Two questions for the reader: 1. Is this the right approach? I am not sure. It seems pretty reasonable to me, but I don't know this area very well. 2. Are the conditions in the new .exp file correct? I mostly copied these from elsewhere, not knowing what is really right. Built and regtested on x86-64 Fedora 15. New test case included. Tom b/gdb/ChangeLog: 2012-02-07 Tom Tromey PR c++/13653: * thread.c (choose_first_inferior): New function. (do_restore_current_thread_cleanup): Handle case where inferior died. diff --git a/gdb/testsuite/gdb.base/inferior-died.c b/gdb/testsuite/gdb.base/inferior-died.c new file mode 100644 index 0000000..66227cf --- /dev/null +++ b/gdb/testsuite/gdb.base/inferior-died.c @@ -0,0 +1,37 @@ +/* Test for fork-related gdb bug + + Copyright 2012 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 +#include + +void function(void) +{ + exit (0); /* Break here */ +} + +int main() +{ + pid_t child = fork (); + + if (child == 0) + function (); + else + waitpid (child, NULL, 0); +} diff --git a/gdb/testsuite/gdb.base/inferior-died.exp b/gdb/testsuite/gdb.base/inferior-died.exp new file mode 100644 index 0000000..458dd61 --- /dev/null +++ b/gdb/testsuite/gdb.base/inferior-died.exp @@ -0,0 +1,56 @@ +# Copyright 2012 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 . + +if { [is_remote target] || ![isnative] } then { + unsupported "inferior-died.exp" + continue +} + +# Until "set follow-fork-mode" and "catch fork" are implemented on +# other targets... +# +if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-*-linux*"]} then { + unsupported "inferior-died.exp" + continue +} + +if { ![support_displaced_stepping] } { + unsupported "inferior-died.exp" + return -1 +} + +set testfile "inferior-died" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c] } { + return -1 +} + +gdb_test_no_output "set detach-on-fork off" +gdb_test_no_output "set target-async on" +gdb_test_no_output "set non-stop on" + +if ![runto_main] { + return +} + +set line [gdb_get_line_number "Break here"] +gdb_breakpoint $srcfile:$line + +gdb_continue_to_breakpoint "breakpoint" + +gdb_test "inferior 2" "Switching to inferior 2.*" +gdb_test "continue" "exited normally.*" diff --git a/gdb/thread.c b/gdb/thread.c index 9a29383..6a667d6 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1074,6 +1074,16 @@ struct current_thread_cleanup int inf_id; }; +/* A helper function for do_restore_current_thread_cleanup. This is + passed to iterate_over_inferiors and simply returns the first + inferior. */ + +static int +choose_first_inferior (struct inferior *inf, void *ignore) +{ + return 1; +} + static void do_restore_current_thread_cleanup (void *arg) { @@ -1091,8 +1101,15 @@ do_restore_current_thread_cleanup (void *arg) restore_current_thread (old->inferior_ptid); else { + struct inferior *inf = find_inferior_id (old->inf_id); + restore_current_thread (null_ptid); - set_current_inferior (find_inferior_id (old->inf_id)); + + /* If the inferior was deleted, choose some other inferior. */ + if (inf == NULL) + inf = iterate_over_inferiors (choose_first_inferior, NULL); + + set_current_inferior (inf); } /* The running state of the originally selected thread may have