From: Simon Marchi via Gdb-patches <gdb-patches@sourceware.org>
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@efficios.com>
Subject: [PATCH 6/6] gdb: don't share aspace/pspace on fork with "detach-on-fork on" and "follow-fork-mode child"
Date: Fri, 10 Sep 2021 16:54:02 -0400 [thread overview]
Message-ID: <20210910205402.3853607-6-simon.marchi@efficios.com> (raw)
In-Reply-To: <20210910205402.3853607-1-simon.marchi@efficios.com>
We found that when handling forks, two inferiors can unexpectedly share
their program space and address space. To reproduce:
1. Using a test program that forks...
2. "set follow-fork-mode child"
3. "set detach-on-fork on" (the default)
4. run to a breakpoint somewhere after the fork
Step 4 should have created a new inferior:
(gdb) info inferiors
Num Description Connection Executable
1 <null> /home/smarchi/build/wt/amd/gdb/fork
* 2 process 251425 1 (native) /home/smarchi/build/wt/amd/gdb/fork
By inspecting the state of GDB, we can see that the two inferiors now
share one program space and one address space:
Inferior 1:
(top-gdb) p inferior_list.m_front.num
$2 = 1
(top-gdb) p inferior_list.m_front.aspace
$3 = (struct address_space *) 0x5595e2520400
(top-gdb) p inferior_list.m_front.pspace
$4 = (struct program_space *) 0x5595e2520440
Inferior 2:
(top-gdb) p inferior_list.m_front.next.num
$5 = 2
(top-gdb) p inferior_list.m_front.next.aspace
$6 = (struct address_space *) 0x5595e2520400
(top-gdb) p inferior_list.m_front.next.pspace
$7 = (struct program_space *) 0x5595e2520440
You can then run inferior 1 again and the two inferiors will still
erroneously share their spaces, but already at this point this is wrong.
The cause of the bad {a,p}space sharing is in follow_fork_inferior.
When following the child and detaching from the parent, we just re-use
the parent's spaces, rather than cloning them. When we switch back to
inferior 1 and run again, we find ourselves with two unrelated inferiors
sharing spaces.
Fix that by creating new spaces for the parent after having moved them
to the child. My initial implementation created new spaces for the
child instead. Doing this breaks doing "next" over fork(). When "next"
start, we record the symtab of the starting location. When the program
stops, we compare that symtab with the symtab the program has stopped
at. If the symtab or the line number has changed, we conclude the
"next" is done. If we create a new program space for the child and copy
the parent's program space to it with clone_program_space, it creates
new symtabs for the child as well. When the child stop, but still on
the fork() line, GDB thinks the "next" is done because the symtab
pointers no longer match. In reality they are two symtab instances that
represent the same file. But moving the spaces to the child and
creating new spaces for the parent, we avoid this problem.
Note that the problem described above happens today with "detach-on-fork
off" and "follow-fork-mode child", because we create new spaces for the
child. This will have to be addressed later.
Test-wise, improve gdb.base/foll-fork.exp to set a breakpoint that is
expected to have a location in each inferiors. Without the fix, when
the two inferiors erroneously share a program space, GDB reports a
single location.
Change-Id: Ifea76e14f87b9f7321fc3a766217061190e71c6e
---
gdb/infrun.c | 39 +++++++++++++++++++++-------
gdb/testsuite/gdb.base/foll-fork.exp | 18 +++++++++++++
2 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index d1ac9b4cbbb..b80884322fa 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -539,25 +539,46 @@ holding the child stopped. Try \"set detach-on-fork\" or \
child_inf->gdbarch = parent_inf->gdbarch;
copy_inferior_target_desc_info (child_inf, parent_inf);
- program_space *parent_pspace = parent_inf->pspace;
-
- /* If this is a vfork child, then the address-space is shared
- with the parent. If we detached from the parent, then we can
- reuse the parent's program/address spaces. */
- if (has_vforked || detach_fork)
+ if (has_vforked)
{
- child_inf->pspace = parent_pspace;
- child_inf->aspace = child_inf->pspace->aspace;
+ /* If this is a vfork child, then the address-space is shared
+ with the parent. */
+ child_inf->aspace = parent_inf->aspace;
+ child_inf->pspace = parent_inf->pspace;
exec_on_vfork (child_inf);
}
+ else if (detach_fork)
+ {
+ /* We follow the child and detach from the parent: move the parent's
+ program space to the child. This simplifies some things, like
+ doing "next" over fork() and landing on the expected line in the
+ child (note, that is broken with "set detach-on-fork off").
+
+ Before assigning brand new spaces for the parent, remove
+ breakpoints from it: because the new pspace won't match
+ currently inserted locations, the normal detach procedure
+ wouldn't remove them, and we would leave them inserted when
+ detaching. */
+ remove_breakpoints_inf (parent_inf);
+
+ child_inf->aspace = parent_inf->aspace;
+ child_inf->pspace = parent_inf->pspace;
+ parent_inf->aspace = new_address_space ();
+ parent_inf->pspace = new program_space (parent_inf->aspace);
+ clone_program_space (parent_inf->pspace, child_inf->pspace);
+
+ /* The parent inferior is still the current one, so keep things
+ in sync. */
+ set_current_program_space (parent_inf->pspace);
+ }
else
{
child_inf->aspace = new_address_space ();
child_inf->pspace = new program_space (child_inf->aspace);
child_inf->removable = 1;
child_inf->symfile_flags = SYMFILE_NO_READ;
- clone_program_space (child_inf->pspace, parent_pspace);
+ clone_program_space (child_inf->pspace, parent_inf->pspace);
}
}
diff --git a/gdb/testsuite/gdb.base/foll-fork.exp b/gdb/testsuite/gdb.base/foll-fork.exp
index 3a0cc2fe456..7f9e1cf87c6 100644
--- a/gdb/testsuite/gdb.base/foll-fork.exp
+++ b/gdb/testsuite/gdb.base/foll-fork.exp
@@ -181,6 +181,24 @@ proc_with_prefix test_follow_fork { follow-fork-mode detach-on-fork cmd } {
".* set breakpoint here.*"
}
}
+
+ # If we end up with two inferiors, verify that they each end up with their
+ # own program space. Do this by setting a breakpoint, if we see two
+ # locations it means there are two program spaces.
+ if {${detach-on-fork} == "off" || ${follow-fork-mode} == "child"} {
+ set bpnum "<unset>"
+ gdb_test_multiple "break callee" "break callee" {
+ -re -wrap "Breakpoint ($::decimal) at $::hex: callee\\. \\(2 locations\\)" {
+ set bpnum $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "$bpnum\\.1 .* inf 1" \
+ "$bpnum\\.2 .* inf 2"] \
+ "info breakpoints"
+ }
}
set reading_in_symbols_re {(?:\r\nReading in symbols for [^\r\n]*)?}
--
2.33.0
next prev parent reply other threads:[~2021-09-10 20:55 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-10 20:53 [PATCH 1/6] gdb.base/foll-fork.exp: remove DUPLICATEs Simon Marchi via Gdb-patches
2021-09-10 20:53 ` [PATCH 2/6] gdb.base/foll-fork.exp: remove gating based on target triplet Simon Marchi via Gdb-patches
2021-09-10 20:53 ` [PATCH 3/6] gdb.base/foll-fork.exp: refactor to restart GDB between each portion of the test Simon Marchi via Gdb-patches
2021-09-10 20:54 ` [PATCH 4/6] gdb.base/foll-fork.exp: rename variables Simon Marchi via Gdb-patches
2021-09-10 20:54 ` [PATCH 5/6] gdb.base/foll-fork.exp: use foreach_with_prefix to handle prefixes Simon Marchi via Gdb-patches
2021-09-10 20:54 ` Simon Marchi via Gdb-patches [this message]
2021-09-10 23:33 ` [PATCH 6/6] gdb: don't share aspace/pspace on fork with "detach-on-fork on" and "follow-fork-mode child" John Baldwin
2021-09-11 3:16 ` Simon Marchi via Gdb-patches
2021-09-11 13:02 ` Simon Marchi via Gdb-patches
2021-09-11 13:03 ` Simon Marchi via Gdb-patches
2021-09-27 19:32 ` Simon Marchi via Gdb-patches
2021-09-28 15:10 ` Tom de Vries via Gdb-patches
2021-09-28 19:12 ` Simon Marchi via Gdb-patches
2021-09-28 19:31 ` Pedro Alves
2021-09-28 19:35 ` Pedro Alves
2021-09-28 23:32 ` Simon Marchi via Gdb-patches
2021-09-28 22:38 ` Tom de Vries via Gdb-patches
2021-09-23 19:23 ` [PATCH 1/6] gdb.base/foll-fork.exp: remove DUPLICATEs Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210910205402.3853607-6-simon.marchi@efficios.com \
--to=gdb-patches@sourceware.org \
--cc=simon.marchi@efficios.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox