)]}'
{
  "commit": "6a534f85cbdb065a307aa96fbbb670948ee135c8",
  "tree": "d6b4db2e9f0f0245791f8b8bb39224cf421b293e",
  "parents": [
    "0ae5b8faded5f79d1fa5bfb257262278676d55f9"
  ],
  "author": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Wed Jul 13 17:16:38 2022 +0100"
  },
  "committer": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Mon Nov 13 14:16:09 2023 +0000"
  },
  "message": "gdb/linux: Delete all other LWPs immediately on ptrace exec event\n\nI noticed that on an Ubuntu 20.04 system, after a following patch\n(\"Step over clone syscall w/ breakpoint,\nTARGET_WAITKIND_THREAD_CLONED\"), the gdb.threads/step-over-exec.exp\nwas passing cleanly, but still, we\u0027d end up with four new unexpected\nGDB core dumps:\n\n\t\t \u003d\u003d\u003d gdb Summary \u003d\u003d\u003d\n\n # of unexpected core files      4\n # of expected passes            48\n\nThat said patch is making the pre-existing\ngdb.threads/step-over-exec.exp testcase (almost silently) expose a\nlatent problem in gdb/linux-nat.c, resulting in a GDB crash when:\n\n #1 - a non-leader thread execs\n #2 - the post-exec program stops somewhere\n #3 - you kill the inferior\n\nInstead of #3 directly, the testcase just returns, which ends up in\ngdb_exit, tearing down GDB, which kills the inferior, and is thus\nequivalent to #3 above.\n\nVis (after said patch is applied):\n\n $ gdb --args ./gdb /home/pedro/gdb/build/gdb/testsuite/outputs/gdb.threads/step-over-exec/step-over-exec-execr-thread-other-diff-text-segs-true\n ...\n (top-gdb) r\n ...\n (gdb) b main\n ...\n (gdb) r\n ...\n Breakpoint 1, main (argc\u003d1, argv\u003d0x7fffffffdb88) at /home/pedro/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/step-over-exec.c:69\n 69        argv0 \u003d argv[0];\n (gdb) c\n Continuing.\n [New Thread 0x7ffff7d89700 (LWP 2506975)]\n Other going in exec.\n Exec-ing /home/pedro/gdb/build/gdb/testsuite/outputs/gdb.threads/step-over-exec/step-over-exec-execr-thread-other-diff-text-segs-true-execd\n process 2506769 is executing new program: /home/pedro/gdb/build/gdb/testsuite/outputs/gdb.threads/step-over-exec/step-over-exec-execr-thread-other-diff-text-segs-true-execd\n\n Thread 1 \"step-over-exec-\" hit Breakpoint 1, main () at /home/pedro/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/step-over-exec-execd.c:28\n 28        foo ();\n (gdb) k\n ...\n Thread 1 \"gdb\" received signal SIGSEGV, Segmentation fault.\n 0x000055555574444c in thread_info::has_pending_waitstatus (this\u003d0x0) at ../../src/gdb/gdbthread.h:393\n 393         return m_suspend.waitstatus_pending_p;\n (top-gdb) bt\n #0  0x000055555574444c in thread_info::has_pending_waitstatus (this\u003d0x0) at ../../src/gdb/gdbthread.h:393\n #1  0x0000555555a884d1 in get_pending_child_status (lp\u003d0x5555579b8230, ws\u003d0x7fffffffd130) at ../../src/gdb/linux-nat.c:1345\n #2  0x0000555555a8e5e6 in kill_unfollowed_child_callback (lp\u003d0x5555579b8230) at ../../src/gdb/linux-nat.c:3564\n #3  0x0000555555a92a26 in gdb::function_view\u003cint (lwp_info*)\u003e::bind\u003cint, lwp_info*\u003e(int (*)(lwp_info*))::{lambda(gdb::fv_detail::erased_callable, lwp_info*)#1}::operator()(gdb::fv_detail::erased_callable, lwp_info*) const (this\u003d0x0, ecall\u003d..., args#0\u003d0x5555579b8230) at ../../src/gdb/../gdbsupport/function-view.h:284\n #4  0x0000555555a92a51 in gdb::function_view\u003cint (lwp_info*)\u003e::bind\u003cint, lwp_info*\u003e(int (*)(lwp_info*))::{lambda(gdb::fv_detail::erased_callable, lwp_info*)#1}::_FUN(gdb::fv_detail::erased_callable, lwp_info*) () at ../../src/gdb/../gdbsupport/function-view.h:278\n #5  0x0000555555a91f84 in gdb::function_view\u003cint (lwp_info*)\u003e::operator()(lwp_info*) const (this\u003d0x7fffffffd210, args#0\u003d0x5555579b8230) at ../../src/gdb/../gdbsupport/function-view.h:247\n #6  0x0000555555a87072 in iterate_over_lwps(ptid_t, gdb::function_view\u003cint (lwp_info*)\u003e) (filter\u003d..., callback\u003d...) at ../../src/gdb/linux-nat.c:864\n #7  0x0000555555a8e732 in linux_nat_target::kill (this\u003d0x55555653af40 \u003cthe_amd64_linux_nat_target\u003e) at ../../src/gdb/linux-nat.c:3590\n #8  0x0000555555cfdc11 in target_kill () at ../../src/gdb/target.c:911\n ...\n\nThe root of the problem is that when a non-leader LWP execs, it just\nchanges its tid to the tgid, replacing the pre-exec leader thread,\nbecoming the new leader.  There\u0027s no thread exit event for the execing\nthread.  It\u0027s as if the old pre-exec LWP vanishes without trace.  The\nptrace man page says:\n\n \"PTRACE_O_TRACEEXEC (since Linux 2.5.46)\n\tStop the tracee at the next execve(2).  A waitpid(2) by the\n\ttracer will return a status value such that\n\n\t  status\u003e\u003e8 \u003d\u003d (SIGTRAP | (PTRACE_EVENT_EXEC\u003c\u003c8))\n\n\tIf the execing thread is not a thread group leader, the thread\n\tID is reset to thread group leader\u0027s ID before this stop.\n\tSince Linux 3.0, the former thread ID can be retrieved with\n\tPTRACE_GETEVENTMSG.\"\n\nWhen the core of GDB processes an exec events, it deletes all the\nthreads of the inferior.  But, that is too late -- deleting the thread\ndoes not delete the corresponding LWP, so we end leaving the pre-exec\nnon-leader LWP stale in the LWP list.  That\u0027s what leads to the crash\nabove -- linux_nat_target::kill iterates over all LWPs, and after the\npatch in question, that code will look for the corresponding\nthread_info for each LWP.  For the pre-exec non-leader LWP still\nlisted, won\u0027t find one.\n\nThis patch fixes it, by deleting the pre-exec non-leader LWP (and\nthread) from the LWP/thread lists as soon as we get an exec event out\nof ptrace.\n\nGDBserver does not need an equivalent fix, because it is already doing\nthis, as side effect of mourning the pre-exec process, in\ngdbserver/linux-low.cc:\n\n  else if (event \u003d\u003d PTRACE_EVENT_EXEC \u0026\u0026 cs.report_exec_events)\n    {\n...\n      /* Delete the execing process and all its threads.  */\n      mourn (proc);\n      switch_to_thread (nullptr);\n\n\nThe crash with gdb.threads/step-over-exec.exp is not observable on\nnewer systems, which postdate the glibc change to move \"libpthread.so\"\ninternals to \"libc.so.6\", because right after the exec, GDB traps a\nload event for \"libc.so.6\", which leads to GDB trying to open\nlibthread_db for the post-exec inferior, and, on such systems that\nsucceeds.  When we load libthread_db, we call\nlinux_stop_and_wait_all_lwps, which, as the name suggests, stops all\nlwps, and then waits to see their stops.  While doing this, GDB\ndetects that the pre-exec stale LWP is gone, and deletes it.\n\nIf we use \"catch exec\" to stop right at the exec before the\n\"libc.so.6\" load event ever happens, and issue \"kill\" right there,\nthen GDB crashes on newer systems as well.  So instead of tweaking\ngdb.threads/step-over-exec.exp to cover the fix, add a new\ngdb.threads/threads-after-exec.exp testcase that uses \"catch exec\".\nThe test also uses the new \"maint info linux-lwps\" command if testing\non Linux native, which also exposes the stale LWP problem with an\nunfixed GDB.\n\nAlso tweak a comment in infrun.c:follow_exec referring to how\nlinux-nat.c used to behave, as it would become stale otherwise.\n\nReviewed-By: Andrew Burgess \u003caburgess@redhat.com\u003e\nChange-Id: I21ec18072c7750f3a972160ae6b9e46590376643\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "4c7eb9be79210ccfb6bc60ff54d0c0712c06b49d",
      "old_mode": 33188,
      "old_path": "gdb/infrun.c",
      "new_id": "c60cfc07aa7e521209ca7eec758f9a658a3d3f89",
      "new_mode": 33188,
      "new_path": "gdb/infrun.c"
    },
    {
      "type": "modify",
      "old_id": "f73e52f9617ea475b202d96cc0d522e36d2e03bb",
      "old_mode": 33188,
      "old_path": "gdb/linux-nat.c",
      "new_id": "97d80053c6f639ea3548fd7f4e761dedbc4abfec",
      "new_mode": 33188,
      "new_path": "gdb/linux-nat.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "b3ed7ec5f6910849c1d09e82145541e6e1dbfd9e",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/threads-after-exec.c"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "cd8adf900d93be4e73282f5765ce21691637f974",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.threads/threads-after-exec.exp"
    }
  ]
}
