public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix AIX thread NULL assertion failure during fork
@ 2023-11-20  7:25 Aditya Kamath1
  2023-11-20 11:27 ` Ulrich Weigand
  0 siblings, 1 reply; 12+ messages in thread
From: Aditya Kamath1 @ 2023-11-20  7:25 UTC (permalink / raw)
  To: Ulrich Weigand, Aditya Kamath1 via Gdb-patches; +Cc: Sangamesh Mallayya


[-- Attachment #1.1: Type: text/plain, Size: 6132 bytes --]

Respected community members,

Hi,

Please find attached a patch. {See: 0001-Fix-AIX-thr-NULL-assertion-failure-during-fork.patch}
This patch is a fix to assertion switch_to_thread: Assertion `thr != NULL' in AIX.

Reproducing this in AIX:-
Consider the program pasted below this email named as multi-thread-fork.c.

This program creates two threads and each thread forks. Only in the case where a user sets to follow the child after fork this assertion failure is seen. In remaining cases {detach_on_fork = on and follow parent, detach on fork = off and follow child and detach on fork off and follow parent} we can debug the code multi-thread-fork.c.

For example, consider output 1 pasted below this email to see the failure.

The root cause:-

Assume we have set detach_on_fork = on and set follow-fork-mode child.
In AIX, on a fork () event we set our status and return our parent ptid from rs6000-aix-nat.c..
Once the object file of the new_inferior or child process is loaded we call pd_enable () to set our thread target and sync our threadlists. In our sync_threadlists we have pbuf having our pthread library threads and gbuf having our GDB threads known to GDB core that have been registered.

The condition if (gptid.is_pid ()) in the function sync_threadlists () will hit when the child process becomes threaded and the child process from ptid_t (pid, 0, 0) is changed to ptid_t (pid, 0, uthid).

After this we return this ptid and the control is now onto GDB generic code where in the infrun.c code, a decision is made in the function follow_fork () in the case TARGET_WAITKIND_FORKED: at line number 897 that if we follow the child, we should switch to thread child of parent as shown below

if (follow_child)
  +898            {
  +899          tp = parent_targ->find_thread (child);
  +900          switch_to_thread (tp);
……..

Here the child is a ptid_t unfortunately with a ptid_t (pid, 0 ,0) instead of ptid_t (pid, 0, tid) which we changed in the sync_threadlists () of aix-thread.c.. So, when a switch to thread here happens ptid_t (pid, 0 ,0) GDB is surprised that this thread does not exist leading to assertion failure.

The FIX:-

While I cannot say with 100% surety that from where GDB core got this ptid and why it did not update to ptid_t (pid, 0, tid) , my observation post debugging is that GDB core would have got ptid_t(pid, 0, 0) from the rs6000-aix-nat.c file, inside the wait () where we did inform GDB by setting a status that this a child process belonging a parent process on a fork event. GDB could not change this ptid it got during the fork event, even though we changed it later via sync_threadlists () from aix-thread.c for the threaded event. Having said that, since in rs6000-aix-nat.c we do not handle any thread related debug behaviour, in our aix-thread.c file I have added a condition such that if there is only one thread that belongs to a process then that process is not multithreaded and need to have thread ptid changed. This fixed the issue as show below this email in Output 2.

Kindly let me know what you think. Have a nice day ahead.

Thanks and regards,
Aditya.



Multi-thread-fork.c
# cat ~/gdb_tests/multi-thread-fork.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>

pthread_barrier_t barrier;

#define NUM_THREADS 2

void *
thread_function (void *arg)
{
  /* This ensures that the breakpoint is only hit after both threads
     are created, so the test can always switch to the non-event
     thread when the breakpoint triggers.  */
  pthread_barrier_wait (&barrier);

  pid_t p;
    p = fork();
    if(p<0)
    {
      perror("fork fail");
      exit(1);
    }
    // child process because return value zero
    else if ( p == 0)
        printf("Hello from Child!\n");

    // parent process because return value non-zero.
    else
        printf("Hello from Parent!\n");
  while (1); /* break here */
}

int
main (void)
{
  int i;

  alarm (300);

  pthread_barrier_init (&barrier, NULL, NUM_THREADS);

  for (i = 0; i < NUM_THREADS; i++)
    {
      pthread_t thread;
      int res;

      res = pthread_create (&thread, NULL,
                            thread_function, NULL);
      assert (res == 0);
    }

  while (1)
    sleep (1);

  return 0;
}


Output 1:-

./gdb ~/gdb_tests/multi-thread-fork
GNU gdb (GDB) 15.0.50.20231117-git
Copyright (C) 2023 Free Software Foundation, Inc.---
Reading symbols from //gdb_tests/multi-thread-fork...
(gdb) set follow-fork-mode child
(gdb) r
Starting program: /gdb_tests/multi-thread-fork
[New Thread 258]
[New Thread 515]
[Attaching after Thread 515 fork to child process 7602578]
[New inferior 2 (process 7602578)]
[Detaching after fork from parent process 6750654]
Hello from Parent!
[Inferior 1 (process 6750654) detached]
Hello from Child!
Hello from Parent!
thread.c:1380: internal-error: switch_to_thread: Assertion `thr != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
0x1008e05db ???
0x1008e07a3 ???
0x1000437f7 ???-------
x100000aff ???
0x100000583 ???
---------------------
thread.c:1380: internal-error: switch_to_thread: Assertion `thr != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) y

Output 2:-

Reading symbols from //gdb_tests/multi-thread-fork...
(gdb) set follow-fork-mode child
(gdb) r
Starting program: /gdb_tests/multi-thread-fork
[New Thread 258]
[New Thread 515]
[Attaching after Thread 515 fork to child process 11403720]
[New inferior 2 (process 11403720)]
[Detaching after fork from parent process 16515532]
[Inferior 1 (process 16515532) detached]
Hello from Parent!
Hello from Child!
Hello from Parent!
Hello from Child!

Thread 2.1 received signal SIGINT, Interrupt.
[Switching to process 11403720]
thread_function (arg=0x0) at //gdb_tests/multi-thread-fork.c:50
50        while (1); /* break here */
(gdb)

[-- Attachment #2: 0001-Fix-AIX-thr-NULL-assertion-failure-during-fork.patch --]
[-- Type: application/octet-stream, Size: 1161 bytes --]

From 58bb04ea840a5988354b855eea0f22c80d0a936b Mon Sep 17 00:00:00 2001
From: Aditya Vidyadhar Kamath <Aditya.Kamath1@ibm.com>
Date: Mon, 20 Nov 2023 01:01:35 -0600
Subject: [PATCH] Fix AIX thr!= NULL assertion failure during fork.

In AIX, while we followed the child process and detach on fork was on we hit this assertion failure.

The reason for the same was GDB core trying to switch to a child thread with tid not set that does not
exist, since child's ptid was changed to ptid_t (pid, 0, tid) in sync_threadlists() as it was threaded.

This patch is a fix for the same.
---
 gdb/aix-thread.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c
index 945b7f6c697..03030dc9351 100644
--- a/gdb/aix-thread.c
+++ b/gdb/aix-thread.c
@@ -927,7 +927,11 @@ sync_threadlists (pid_t pid)
 	      /* This is to make the main process thread now look
 		 like a thread.  */
 
-	      if (gptid.is_pid ())
+		  if (pcount == gcount == 1)
+		{
+		    gi++;pi++;
+		}
+	    else if (gptid.is_pid ())
 		{
 		  tp = proc_target->find_thread (gptid);
 		  thread_change_ptid (proc_target, gptid, pptid);
-- 
2.41.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-11-23  6:07 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-20  7:25 [PATCH] Fix AIX thread NULL assertion failure during fork Aditya Kamath1
2023-11-20 11:27 ` Ulrich Weigand
2023-11-21  7:30   ` Aditya Kamath1
2023-11-21 12:17     ` Ulrich Weigand
2023-11-22 10:48       ` Aditya Kamath1
2023-11-22 11:30         ` Ulrich Weigand
2023-11-22 13:58           ` Aditya Kamath1
2023-11-22 14:14             ` Aditya Kamath1
2023-11-22 15:33               ` Ulrich Weigand
2023-11-22 16:22                 ` Aditya Kamath1
2023-11-22 18:30                   ` Ulrich Weigand
2023-11-23  6:06                     ` Aditya Kamath1

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).