(root)/
glibc-2.38/
stdlib/
test-dlclose-exit-race.c
       1  /* Test for exit/dlclose race (Bug 22180).
       2     Copyright (C) 2017-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     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* This file must be run from within a directory called "stdlib".  */
      20  
      21  /* This test verifies that when dlopen in one thread races against exit
      22     in another thread, we don't call registered destructor twice.
      23  
      24     Expected result:
      25       second
      26       first
      27       ... clean termination
      28  */
      29  
      30  #include <stdio.h>
      31  #include <stdlib.h>
      32  #include <errno.h>
      33  #include <semaphore.h>
      34  #include <support/check.h>
      35  #include <support/xdlfcn.h>
      36  #include <support/xthread.h>
      37  
      38  /* Semaphore to ensure we have a happens-before between the first function
      39     starting and exit being called.  */
      40  sem_t order1;
      41  
      42  /* Semaphore to ensure we have a happens-before between the second function
      43     starting and the first function returning.  */
      44  sem_t order2;
      45  
      46  void *
      47  exit_thread (void *arg)
      48  {
      49    /* Wait for the dlclose to start...  */
      50    sem_wait (&order1);
      51    /* Then try to run the exit sequence which should call all
      52       __cxa_atexit registered functions and in parallel with
      53       the executing dlclose().  */
      54    exit (0);
      55  }
      56  
      57  
      58  void
      59  last (void)
      60  {
      61    /* Let dlclose thread proceed.  */
      62    sem_post (&order2);
      63  }
      64  
      65  int
      66  main (void)
      67  {
      68    int value;
      69    void *dso;
      70    pthread_t thread;
      71  
      72    atexit (last);
      73  
      74    dso = xdlopen ("$ORIGIN/test-dlclose-exit-race-helper.so",
      75  		 RTLD_NOW|RTLD_GLOBAL);
      76    if ((value = pthread_create (&thread, NULL, exit_thread, NULL)) != 0)
      77      {
      78        /* If pthread_create fails, then exit() is called in the main
      79  	 thread instead of a second thread, so the semaphore post that
      80  	 would have happened in 'last' gets blocked behind the call to
      81  	 first() - which is waiting on the semaphore, and thus
      82  	 hangs.  */
      83        sem_post (&order2);
      84        errno = value;
      85        FAIL_EXIT1 ("pthread_create: %m");
      86      }
      87  
      88    xdlclose (dso);
      89    xpthread_join (thread);
      90  
      91    FAIL_EXIT1 ("Did not terminate via exit(0) in exit_thread() as expected.");
      92  }