* RFA: fix PR breakpoints/13776
@ 2012-02-28 17:51 Tom Tromey
2012-02-28 18:27 ` Tom Tromey
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Tom Tromey @ 2012-02-28 17:51 UTC (permalink / raw)
To: gdb-patches
I'd appreciate comments on this patch.
I have no idea whether it is the best way to fix the problem.
Bug 13776 concerns 'next'ing over an exit. For the trivial:
#include <stdlib.h>
int
main (void)
{
exit (0);
}
We get this behavior:
(gdb) start
Temporary breakpoint 1, main () at exit0.c:5
5 exit (0);
(gdb) next
[Inferior 1 (process 2428) exited normally]
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
warning: Error removing breakpoint 0
The bug is that exit_inferior ends up calling delete_longjmp_breakpoint,
which tries to delete the longjmp breakpoints -- but as the inferior is
dead, this fails.
This patch fixes this problem by moving the breakpoint_init_inferior
call earlier in generic_mourn_inferior. This causes the breakpoints to
be marked as uninserted before they are deleted.
While doing this I noticed that after the inferior exits, we are left
with a step-resume breakpoint:
(gdb) maint info b
Num Type Disp Enb Address What
[...]
0 step resume dstp y 0x00000000004004d2 inf 1 thread 1
stop only in thread 1
The breakpoint.c patch causes this to be removed as well.
Built and regtested on x86-64 Fedora 16.
Tom
2012-02-28 Tom Tromey <tromey@redhat.com>
PR breakpoints/13776:
* target.c (generic_mourn_inferior): Call breakpoint_init_inferior
earlier.
* breakpoint.c (breakpoint_init_inferior): Delete step-resume
breakpoints.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index db05b97..048cc63 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3341,6 +3341,10 @@ breakpoint_init_inferior (enum inf_context context)
(gdb) tar rem :9999 # remote Windows gdbserver.
*/
+ case bp_step_resume:
+
+ /* Also remove step-resume breakpoints. */
+
delete_breakpoint (b);
break;
diff --git a/gdb/target.c b/gdb/target.c
index 1f408f6..65a6c23 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3583,13 +3583,14 @@ generic_mourn_inferior (void)
ptid = inferior_ptid;
inferior_ptid = null_ptid;
+ breakpoint_init_inferior (inf_exited);
+
if (!ptid_equal (ptid, null_ptid))
{
int pid = ptid_get_pid (ptid);
exit_inferior (pid);
}
- breakpoint_init_inferior (inf_exited);
registers_changed ();
reopen_exec_file ();
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-02-28 17:51 RFA: fix PR breakpoints/13776 Tom Tromey
@ 2012-02-28 18:27 ` Tom Tromey
2012-02-28 20:35 ` Jan Kratochvil
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Tom Tromey @ 2012-02-28 18:27 UTC (permalink / raw)
To: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> I'd appreciate comments on this patch.
Tom> I have no idea whether it is the best way to fix the problem.
I somehow forgot to turn the test case into a patch against the test
suite.
So, please look at the patch; but know that I will not check anything in
until the test case is written up.
thanks,
Tom
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-02-28 17:51 RFA: fix PR breakpoints/13776 Tom Tromey
2012-02-28 18:27 ` Tom Tromey
@ 2012-02-28 20:35 ` Jan Kratochvil
2012-02-28 21:05 ` Doug Evans
2012-02-29 20:07 ` Pedro Alves
3 siblings, 0 replies; 8+ messages in thread
From: Jan Kratochvil @ 2012-02-28 20:35 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Tue, 28 Feb 2012 18:26:48 +0100, Tom Tromey wrote:
> I'd appreciate comments on this patch.
> I have no idea whether it is the best way to fix the problem.
I find it OK although I already made some such mistakes in the past.
Thanks,
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-02-28 17:51 RFA: fix PR breakpoints/13776 Tom Tromey
2012-02-28 18:27 ` Tom Tromey
2012-02-28 20:35 ` Jan Kratochvil
@ 2012-02-28 21:05 ` Doug Evans
2012-02-29 20:07 ` Pedro Alves
3 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2012-02-28 21:05 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Tue, Feb 28, 2012 at 9:26 AM, Tom Tromey <tromey@redhat.com> wrote:
> I'd appreciate comments on this patch.
> [...]
> This patch fixes this problem by moving the breakpoint_init_inferior
> call earlier in generic_mourn_inferior. This causes the breakpoints to
> be marked as uninserted before they are deleted.
> [...]
> diff --git a/gdb/target.c b/gdb/target.c
> index 1f408f6..65a6c23 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -3583,13 +3583,14 @@ generic_mourn_inferior (void)
> ptid = inferior_ptid;
> inferior_ptid = null_ptid;
>
> + breakpoint_init_inferior (inf_exited);
> +
> if (!ptid_equal (ptid, null_ptid))
> {
> int pid = ptid_get_pid (ptid);
> exit_inferior (pid);
> }
>
> - breakpoint_init_inferior (inf_exited);
> registers_changed ();
>
> reopen_exec_file ();
A comment right before the new breakpoint_init_inferior call to
explain why it lives there would be useful to future readers of the
code.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-02-28 17:51 RFA: fix PR breakpoints/13776 Tom Tromey
` (2 preceding siblings ...)
2012-02-28 21:05 ` Doug Evans
@ 2012-02-29 20:07 ` Pedro Alves
2012-03-02 17:39 ` Tom Tromey
3 siblings, 1 reply; 8+ messages in thread
From: Pedro Alves @ 2012-02-29 20:07 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 02/28/2012 05:26 PM, Tom Tromey wrote:
> I'd appreciate comments on this patch.
> I have no idea whether it is the best way to fix the problem.
>
> Bug 13776 concerns 'next'ing over an exit. For the trivial:
>
> #include <stdlib.h>
> int
> main (void)
> {
> exit (0);
> }
>
> We get this behavior:
>
> (gdb) start
> Temporary breakpoint 1, main () at exit0.c:5
> 5 exit (0);
> (gdb) next
> [Inferior 1 (process 2428) exited normally]
> warning: Error removing breakpoint 0
> warning: Error removing breakpoint 0
> warning: Error removing breakpoint 0
>
> The bug is that exit_inferior ends up calling delete_longjmp_breakpoint,
> which tries to delete the longjmp breakpoints -- but as the inferior is
> dead, this fails.
>
> This patch fixes this problem by moving the breakpoint_init_inferior
> call earlier in generic_mourn_inferior. This causes the breakpoints to
> be marked as uninserted before they are deleted.
>
> While doing this I noticed that after the inferior exits, we are left
> with a step-resume breakpoint:
>
> (gdb) maint info b
> Num Type Disp Enb Address What
> [...]
> 0 step resume dstp y 0x00000000004004d2 inf 1 thread 1
> stop only in thread 1
>
> The breakpoint.c patch causes this to be removed as well.
>
> Built and regtested on x86-64 Fedora 16.
>
> Tom
>
> 2012-02-28 Tom Tromey <tromey@redhat.com>
>
> PR breakpoints/13776:
> * target.c (generic_mourn_inferior): Call breakpoint_init_inferior
> earlier.
> * breakpoint.c (breakpoint_init_inferior): Delete step-resume
> breakpoints.
>
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index db05b97..048cc63 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -3341,6 +3341,10 @@ breakpoint_init_inferior (enum inf_context context)
> (gdb) tar rem :9999 # remote Windows gdbserver.
> */
>
> + case bp_step_resume:
> +
> + /* Also remove step-resume breakpoints. */
> +
> delete_breakpoint (b);
> break;
>
> diff --git a/gdb/target.c b/gdb/target.c
> index 1f408f6..65a6c23 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -3583,13 +3583,14 @@ generic_mourn_inferior (void)
> ptid = inferior_ptid;
> inferior_ptid = null_ptid;
>
> + breakpoint_init_inferior (inf_exited);
> +
If you do this before exit_inferior, then the
breakpoint_init_inferior change is wrong, because the
clear_thread_inferior_resources will touch already released memory.
Note with valgrind:
main () at stepexit.c:6
6 exit (0);
(gdb) n
[Inferior 1 (process 11456) exited normally]
==11452== Invalid write of size 4
==11452== at 0x5B38C2: clear_thread_inferior_resources (thread.c:105)
==11452== by 0x5B3E62: delete_thread_1 (thread.c:294)
==11452== by 0x5B3EC7: delete_thread (thread.c:311)
==11452== by 0x6CDFC0: delete_thread_of_inferior (inferior.c:175)
==11452== by 0x5B3FE8: iterate_over_threads (thread.c:368)
==11452== by 0x6CE1C4: exit_inferior_1 (inferior.c:272)
==11452== by 0x6CE25B: exit_inferior (inferior.c:295)
==11452== by 0x5E542E: generic_mourn_inferior (target.c:3591)
==11452== by 0x484C1B: inf_ptrace_mourn_inferior (inf-ptrace.c:181)
==11452== by 0x491F19: linux_nat_mourn_inferior (linux-nat.c:4227)
==11452== by 0x5E3F89: target_mourn_inferior (target.c:2755)
==11452== by 0x5A3353: handle_inferior_event (infrun.c:3405)
==11452== Address 0x4cba398 is 24 bytes inside a block of size 184 free'd
==11452== at 0x4A0662E: free (vg_replace_malloc.c:366)
==11452== by 0x6DB4F0: xfree (common-utils.c:107)
==11452== by 0x5407EB: delete_breakpoint (breakpoint.c:12666)
==11452== by 0x52FE08: breakpoint_init_inferior (breakpoint.c:3348)
==11452== by 0x5E53BB: generic_mourn_inferior (target.c:3586)
==11452== by 0x484C1B: inf_ptrace_mourn_inferior (inf-ptrace.c:181)
==11452== by 0x491F19: linux_nat_mourn_inferior (linux-nat.c:4227)
==11452== by 0x5E3F89: target_mourn_inferior (target.c:2755)
==11452== by 0x5A3353: handle_inferior_event (infrun.c:3405)
==11452== by 0x5A1CB5: wait_for_inferior (infrun.c:2709)
==11452== by 0x5A0E9B: proceed (infrun.c:2278)
==11452== by 0x599EFB: step_once (infcmd.c:1067)
==11452==
(gdb)
step-resume breakpoint lifetime isn't the prettiest thing...
> if (!ptid_equal (ptid, null_ptid))
> {
> int pid = ptid_get_pid (ptid);
> exit_inferior (pid);
> }
>
> - breakpoint_init_inferior (inf_exited);
> registers_changed ();
>
> reopen_exec_file ();
We can call mark_breakpoints_out before that exit_inferior to only
mark the breakpoints uninserted, while leaving the rest of the
breakpoint_init_inferior work do be done where it is.
Also note how we're careful to not delete step-resume and
exception resume breakpoints directly in clear_thread_inferior_resources.
static void
clear_thread_inferior_resources (struct thread_info *tp)
{
/* NOTE: this will take care of any left-over step_resume breakpoints,
but not any user-specified thread-specific breakpoints. We can not
delete the breakpoint straight-off, because the inferior might not
be stopped at the moment. */
if (tp->control.step_resume_breakpoint)
{
tp->control.step_resume_breakpoint->disposition = disp_del_at_next_stop;
tp->control.step_resume_breakpoint = NULL;
}
if (tp->control.exception_resume_breakpoint)
{
tp->control.exception_resume_breakpoint->disposition
= disp_del_at_next_stop;
tp->control.exception_resume_breakpoint = NULL;
}
bpstat_clear (&tp->control.stop_bpstat);
do_all_intermediate_continuations_thread (tp, 1);
do_all_continuations_thread (tp, 1);
delete_longjmp_breakpoint (tp->num);
}
I think longjmp breakpoints should get the same treatment, though this
isn't strictly necessary for the exit case (though it is for
pthread_exit on targets without thread exit notifications, like remote).
With this, the problem is gone, in both sync and async modes, and we
have no step-resume breakpoint left behind. Maybe we should also
delete longjmp and exception-resume breakpoints similarly in
breakpoint_init_inferior, but since they're always deleted either through
a cleanup or a continuation I couldn't find a way to leave them stale.
There's probably a way with some path that throws an error before the
continuation that deletes the breakpoint is reached. I'm leaving that
out for now.
WDTY?
2012-02-29 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
PR breakpoints/13776:
* breakpoint.c (breakpoint_init_inferior): Delete step-resume
breakpoints.
(delete_longjmp_breakpoint_at_next_stop): New.
* breakpoint.h (delete_longjmp_breakpoint_at_next_stop): Declare.
* target.c (generic_mourn_inferior): Call mark_breakpoints_out
before deleting the inferior. Add comments.
* thread.c (clear_thread_inferior_resources): Don't delete lonjmp
breakpoints immediately, but only on next stop. Move that code
next to where we mark other breakpoints for deletion.
---
gdb/breakpoint.c | 17 +++++++++++++++++
gdb/breakpoint.h | 3 +++
gdb/target.c | 9 +++++++++
gdb/thread.c | 4 ++--
4 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index db05b97..f634d97 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3341,6 +3341,10 @@ breakpoint_init_inferior (enum inf_context context)
(gdb) tar rem :9999 # remote Windows gdbserver.
*/
+ case bp_step_resume:
+
+ /* Also remove step-resume breakpoints. */
+
delete_breakpoint (b);
break;
@@ -6625,6 +6629,19 @@ delete_longjmp_breakpoint (int thread)
}
void
+delete_longjmp_breakpoint_at_next_stop (int thread)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ if (b->type == bp_longjmp || b->type == bp_exception)
+ {
+ if (b->thread == thread)
+ b->disposition = disp_del_at_next_stop;
+ }
+}
+
+void
enable_overlay_breakpoints (void)
{
struct breakpoint *b;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7e8c597..5b5172e 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1254,6 +1254,9 @@ extern void set_longjmp_breakpoint (struct thread_info *tp,
struct frame_id frame);
extern void delete_longjmp_breakpoint (int thread);
+/* Mark all longjmp breakpoints from THREAD for later deletion. */
+extern void delete_longjmp_breakpoint_at_next_stop (int thread);
+
extern void enable_overlay_breakpoints (void);
extern void disable_overlay_breakpoints (void);
diff --git a/gdb/target.c b/gdb/target.c
index 1f408f6..d29d37a 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3583,13 +3583,22 @@ generic_mourn_inferior (void)
ptid = inferior_ptid;
inferior_ptid = null_ptid;
+ /* Mark breakpoints uninserted in case something tries to delete a
+ breakpoint while we delete the inferior's threads (which would
+ fail, since the inferior is long gone). */
+ mark_breakpoints_out ();
+
if (!ptid_equal (ptid, null_ptid))
{
int pid = ptid_get_pid (ptid);
exit_inferior (pid);
}
+ /* Note this wipes step-resume breakpoints, so needs to be done
+ after exit_inferior, which ends up referencing the step-resume
+ breakpoints through clear_thread_inferior_resources. */
breakpoint_init_inferior (inf_exited);
+
registers_changed ();
reopen_exec_file ();
diff --git a/gdb/thread.c b/gdb/thread.c
index 22d8b23..97f283c 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -113,12 +113,12 @@ clear_thread_inferior_resources (struct thread_info *tp)
tp->control.exception_resume_breakpoint = NULL;
}
+ delete_longjmp_breakpoint_at_next_stop (tp->num);
+
bpstat_clear (&tp->control.stop_bpstat);
do_all_intermediate_continuations_thread (tp, 1);
do_all_continuations_thread (tp, 1);
-
- delete_longjmp_breakpoint (tp->num);
}
static void
--
Pedro Alves
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-02-29 20:07 ` Pedro Alves
@ 2012-03-02 17:39 ` Tom Tromey
2012-03-02 18:15 ` Doug Evans
2012-03-02 19:05 ` Pedro Alves
0 siblings, 2 replies; 8+ messages in thread
From: Tom Tromey @ 2012-03-02 17:39 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> If you do this before exit_inferior, then the
Pedro> breakpoint_init_inferior change is wrong, because the
Pedro> clear_thread_inferior_resources will touch already released memory.
Ugh, thanks for noticing.
I should have tried this.
Pedro> WDTY?
I think the patch is fine.
Pedro> 2012-02-29 Tom Tromey <tromey@redhat.com>
Pedro> Pedro Alves <palves@redhat.com>
... but it is silly to put my name on it since I think I wrote one line
in the result :)
Here is a test case for the bug.
I can commit it first if you'd prefer.
Tom
2012-03-02 Tom Tromey <tromey@redhat.com>
* gdb.base/nextoverexit.c: New file.
* gdb.base/nextoverexit.exp: New file.
diff --git a/gdb/testsuite/gdb.base/nextoverexit.c b/gdb/testsuite/gdb.base/nextoverexit.c
new file mode 100644
index 0000000..125d68f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nextoverexit.c
@@ -0,0 +1,23 @@
+/* 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+int
+main (void)
+{
+ exit (0);
+}
diff --git a/gdb/testsuite/gdb.base/nextoverexit.exp b/gdb/testsuite/gdb.base/nextoverexit.exp
new file mode 100644
index 0000000..fecbd58
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nextoverexit.exp
@@ -0,0 +1,33 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+set testfile "nextoverexit"
+set executable $testfile
+set srcfile $testfile.c
+set binfile $objdir/$subdir/$testfile
+
+if {[prepare_for_testing $testfile.exp $testfile $testfile.c]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+# Make sure we do not see any warnings.
+gdb_test_multiple "next" "next over exit" {
+ -re "$inferior_exited_re normally.\[\r\n\]+$gdb_prompt $" {
+ pass "next over exit"
+ }
+}
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-03-02 17:39 ` Tom Tromey
@ 2012-03-02 18:15 ` Doug Evans
2012-03-02 19:05 ` Pedro Alves
1 sibling, 0 replies; 8+ messages in thread
From: Doug Evans @ 2012-03-02 18:15 UTC (permalink / raw)
To: Tom Tromey; +Cc: Pedro Alves, gdb-patches
On Fri, Mar 2, 2012 at 9:39 AM, Tom Tromey <tromey@redhat.com> wrote:
> ... but it is silly to put my name on it since I think I wrote one line
> in the result :)
[fwiw]
Au contraire. There's more to it than just writing the final version
of the patch, and I would be uncomfortable with the potential
precedent.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: RFA: fix PR breakpoints/13776
2012-03-02 17:39 ` Tom Tromey
2012-03-02 18:15 ` Doug Evans
@ 2012-03-02 19:05 ` Pedro Alves
1 sibling, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2012-03-02 19:05 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/02/2012 05:39 PM, Tom Tromey wrote:
> I think the patch is fine.
>
> Pedro> 2012-02-29 Tom Tromey <tromey@redhat.com>
> Pedro> Pedro Alves <palves@redhat.com>
>
> ... but it is silly to put my name on it since I think I wrote one line
> in the result :)
Nah, my version is clearly derived from yours. I've checked it in now.
>
> Here is a test case for the bug.
> I can commit it first if you'd prefer.
>
> Tom
>
> 2012-03-02 Tom Tromey <tromey@redhat.com>
>
> * gdb.base/nextoverexit.c: New file.
> * gdb.base/nextoverexit.exp: New file.
Looks good to me.
--
Pedro Alves
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2012-03-02 19:05 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-28 17:51 RFA: fix PR breakpoints/13776 Tom Tromey
2012-02-28 18:27 ` Tom Tromey
2012-02-28 20:35 ` Jan Kratochvil
2012-02-28 21:05 ` Doug Evans
2012-02-29 20:07 ` Pedro Alves
2012-03-02 17:39 ` Tom Tromey
2012-03-02 18:15 ` Doug Evans
2012-03-02 19:05 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox