From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16127 invoked by alias); 29 Jun 2009 10:09:38 -0000 Received: (qmail 16117 invoked by uid 22791); 29 Jun 2009 10:09:37 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx2.redhat.com (HELO mx2.redhat.com) (66.187.237.31) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 29 Jun 2009 10:09:27 +0000 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n5TA9PG4030049 for ; Mon, 29 Jun 2009 06:09:25 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n5TA9Ots011616 for ; Mon, 29 Jun 2009 06:09:24 -0400 Received: from host0.dyn.jankratochvil.net (sebastian-int.corp.redhat.com [172.16.52.221]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n5TA9NWU027212 for ; Mon, 29 Jun 2009 06:09:24 -0400 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.3/8.14.3) with ESMTP id n5TA9NG6027770 for ; Mon, 29 Jun 2009 12:09:23 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.3/8.14.3/Submit) id n5TA9MdV027769 for gdb-patches@sourceware.org; Mon, 29 Jun 2009 12:09:22 +0200 Date: Mon, 29 Jun 2009 10:09:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Subject: [patch] Fix internal-error on dead LWPs with no associated thread Message-ID: <20090629100922.GA26882@host0.dyn.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.19 (2009-01-05) X-IsSubscribed: yes 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: 2009-06/txt/msg00802.txt.bz2 Hi, original bugreport: https://bugzilla.redhat.com/show_bug.cgi?id=471819 linux-nat.c:1662: internal-error: linux_nat_resume: Assertion `lp != NULL' failed. A reproducing testcase included. No regressions on {x86_64,i686}-fedora-linux-gnu. Thanks, Jan gdb/ 2009-06-27 Jan Kratochvil Fix internal error on dead LWPs with no associated thread. * linux-nat.c (num_lwps): Do not count DEAD LWPs. (delete_lwp): Only set LP as DEAD if it is INFERIOR_PTID. (iterate_over_lwps): Skip DEAD LPs. Discard DEAD LPs not in INFERIOR_PTID. (linux_nat_resume): Do not resume DEAD LPs. Extend the debug message. * linux-nat.h (struct lwp_info): New field `dead'. gdb/testsuite/ 2009-06-27 Jan Kratochvil * gdb.threads/current-lwp-dead.exp, gdb.threads/current-lwp-dead.c: New. --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -941,7 +941,7 @@ num_lwps (int pid) struct lwp_info *lp; for (lp = lwp_list; lp; lp = lp->next) - if (ptid_get_pid (lp->ptid) == pid) + if (ptid_get_pid (lp->ptid) == pid && !lp->dead) count++; return count; @@ -991,6 +991,13 @@ delete_lwp (ptid_t ptid) if (!lp) return; + if (ptid_equal (ptid, inferior_ptid)) + { + /* Delay the deletion the same way as in delete_thread_1. */ + lp->dead = 1; + return; + } + if (lpprev) lpprev->next = lp->next; else @@ -1063,6 +1070,15 @@ iterate_over_lwps (ptid_t filter, { lpnext = lp->next; + /* Ignored already dead LWPs. Moreover delete them if we no longer have + to keep them around. */ + if (lp->dead) + { + if (!ptid_equal (lp->ptid, inferior_ptid)) + delete_lwp (lp->ptid); + continue; + } + if (ptid_match (lp->ptid, filter)) { if ((*callback) (lp, data)) @@ -1732,15 +1748,19 @@ linux_nat_resume (struct target_ops *ops, /* Convert to something the lower layer understands. */ ptid = pid_to_ptid (GET_LWP (lp->ptid)); - linux_ops->to_resume (linux_ops, ptid, step, signo); - memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + if (!lp->dead) + { + linux_ops->to_resume (linux_ops, ptid, step, signo); + memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + } if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, - "LLR: %s %s, %s (resume event thread)\n", + "LLR: %s %s, %s, %s (resume event thread)\n", step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", target_pid_to_str (ptid), - signo ? strsignal (signo) : "0"); + signo ? strsignal (signo) : "0", + lp->dead ? "dead" : "alive"); restore_child_signals_mask (&prev_mask); if (target_can_async_p ()) --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -32,6 +32,12 @@ struct lwp_info and overall process id. */ ptid_t ptid; + /* If this flag is set, the lwp is known to be dead already (exit + event already received in a my_waitpid()). Such LWP should not longer be + iterated and it is being kept only temporarily if it is still referenced + by INFERIOR_PTID. */ + int dead; + /* Non-zero if this LWP is cloned. In this context "cloned" means that the LWP is reporting to its parent using a signal other than SIGCHLD. */ new file mode 100644 --- /dev/null +++ b/gdb/testsuite/gdb.threads/current-lwp-dead.c @@ -0,0 +1,75 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 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 . + + Do not use threads as we need to exploit a bug in LWP code masked by the + threads code otherwise. + + INFERIOR_PTID must point to exited LWP. Here we use the initial LWP as it + is automatically INFERIOR_PTID for GDB. + + Finally we need to call target_resume (RESUME_ALL, ...) which we invoke by + NEW_THREAD_EVENT (called from the new LWP as initial LWP is exited now). */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#define STACK_SIZE 0x1000 + +static int +fn_abort (void *unused) +{ + return 0; /* at-fn_abort */ +} + +static int +fn (void *unused) +{ + int i; + unsigned char *stack; + int new_pid; + + i = sleep (1); + assert (i == 0); + + stack = malloc (STACK_SIZE); + assert (stack != NULL); + + new_pid = clone (fn_abort, stack + STACK_SIZE, CLONE_FILES | CLONE_VM, NULL, + NULL, NULL, NULL); + assert (new_pid > 0); + + return 0; +} + +int +main (int argc, char **argv) +{ + unsigned char *stack; + int new_pid; + + stack = malloc (STACK_SIZE); + assert (stack != NULL); + + new_pid = clone (fn, stack + STACK_SIZE, CLONE_FILES | CLONE_VM, NULL, NULL, + NULL, NULL); + assert (new_pid > 0); + + return 0; +} new file mode 100644 --- /dev/null +++ b/gdb/testsuite/gdb.threads/current-lwp-dead.exp @@ -0,0 +1,31 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2009 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 . + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@gnu.org + +if { [prepare_for_testing current-lwp-dead.exp current-lwp-dead] } { + return -1 +} + +if {[runto_main] <= 0} { + untested current-lwp-dead.exp + return -1 +} + +gdb_breakpoint "fn_abort" +gdb_continue_to_breakpoint "fn_abort" ".*at-fn_abort.*"