(root)/
glibc-2.38/
sysdeps/
pthread/
tst-atfork3.c
       1  /* Check if pthread_atfork handler can call dlclose (BZ#24595).
       2     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <http://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdio.h>
      20  #include <pthread.h>
      21  #include <unistd.h>
      22  #include <stdlib.h>
      23  #include <stdbool.h>
      24  
      25  #include <support/check.h>
      26  #include <support/xthread.h>
      27  #include <support/capture_subprocess.h>
      28  #include <support/xdlfcn.h>
      29  
      30  /* Check if pthread_atfork handlers do not deadlock when calling a function
      31     that might alter the internal fork handle list, such as dlclose.
      32  
      33     The test registers a callback set with pthread_atfork(), dlopen() a shared
      34     library (nptl/tst-atfork3mod.c), calls an exported symbol from the library
      35     (which in turn also registers atfork handlers), and calls fork to trigger
      36     the callbacks.  */
      37  
      38  static void *handler;
      39  static bool run_dlclose_prepare;
      40  static bool run_dlclose_parent;
      41  static bool run_dlclose_child;
      42  
      43  static void
      44  prepare (void)
      45  {
      46    if (run_dlclose_prepare)
      47      xdlclose (handler);
      48  }
      49  
      50  static void
      51  parent (void)
      52  {
      53    if (run_dlclose_parent)
      54      xdlclose (handler);
      55  }
      56  
      57  static void
      58  child (void)
      59  {
      60    if (run_dlclose_child)
      61      xdlclose (handler);
      62  }
      63  
      64  static void
      65  proc_func (void *closure)
      66  {
      67  }
      68  
      69  static void
      70  do_test_generic (bool dlclose_prepare, bool dlclose_parent, bool dlclose_child)
      71  {
      72    run_dlclose_prepare = dlclose_prepare;
      73    run_dlclose_parent = dlclose_parent;
      74    run_dlclose_child = dlclose_child;
      75  
      76    handler = xdlopen ("tst-atfork3mod.so", RTLD_NOW);
      77  
      78    int (*atfork3mod_func)(void);
      79    atfork3mod_func = xdlsym (handler, "atfork3mod_func");
      80  
      81    atfork3mod_func ();
      82  
      83    struct support_capture_subprocess proc
      84      = support_capture_subprocess (proc_func, NULL);
      85    support_capture_subprocess_check (&proc, "tst-atfork3", 0, sc_allow_none);
      86  
      87    handler = atfork3mod_func = NULL;
      88  
      89    support_capture_subprocess_free (&proc);
      90  }
      91  
      92  static void *
      93  thread_func (void *closure)
      94  {
      95    return NULL;
      96  }
      97  
      98  static int
      99  do_test (void)
     100  {
     101    {
     102      /* Make the process acts as multithread.  */
     103      pthread_attr_t attr;
     104      xpthread_attr_init (&attr);
     105      xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
     106      xpthread_create (&attr, thread_func, NULL);
     107    }
     108  
     109    TEST_COMPARE (pthread_atfork (prepare, parent, child), 0);
     110  
     111    do_test_generic (true  /* prepare */, false /* parent */, false /* child */);
     112    do_test_generic (false /* prepare */, true  /* parent */, false /* child */);
     113    do_test_generic (false /* prepare */, false /* parent */, true  /* child */);
     114  
     115    return 0;
     116  }
     117  
     118  #include <support/test-driver.c>