(root)/
glibc-2.38/
nptl/
tst-stack4.c
       1  /* Test DTV size overflow when pthread_create reuses old DTV and TLS is
       2     used by dlopened shared object.
       3     Copyright (C) 2014-2023 Free Software Foundation, Inc.
       4     This file is part of the GNU C Library.
       5  
       6     The GNU C Library is free software; you can redistribute it and/or
       7     modify it under the terms of the GNU Lesser General Public
       8     License as published by the Free Software Foundation; either
       9     version 2.1 of the License, or (at your option) any later version.
      10  
      11     The GNU C Library is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14     Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public
      17     License along with the GNU C Library; if not, see
      18     <https://www.gnu.org/licenses/>.  */
      19  
      20  #include <stdio.h>
      21  #include <stdint.h>
      22  #include <dlfcn.h>
      23  #include <assert.h>
      24  #include <pthread.h>
      25  
      26  /* The choices of thread count, and file counts are arbitrary.
      27     The point is simply to run enough threads that an exiting
      28     thread has it's stack reused by another thread at the same
      29     time as new libraries have been loaded.  */
      30  #define DSO_SHARED_FILES 20
      31  #define DSO_OPEN_THREADS 20
      32  #define DSO_EXEC_THREADS 2
      33  
      34  /* Used to make sure that only one thread is calling dlopen and dlclose
      35     at a time.  */
      36  pthread_mutex_t g_lock;
      37  
      38  typedef void (*function) (void);
      39  
      40  void *
      41  dso_invoke(void *dso_fun)
      42  {
      43    function *fun_vec = (function *) dso_fun;
      44    int dso;
      45  
      46    for (dso = 0; dso < DSO_SHARED_FILES; dso++)
      47      (*fun_vec[dso]) ();
      48  
      49    pthread_exit (NULL);
      50  }
      51  
      52  void *
      53  dso_process (void * p)
      54  {
      55    void *handle[DSO_SHARED_FILES];
      56    function fun_vec[DSO_SHARED_FILES];
      57    char dso_path[DSO_SHARED_FILES][100];
      58    int dso;
      59    int t = (int) (uintptr_t) p;
      60  
      61    /* Open DSOs and get a function.  */
      62    for (dso = 0; dso < DSO_SHARED_FILES; dso++)
      63      {
      64        sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
      65  
      66        pthread_mutex_lock (&g_lock);
      67  
      68        handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
      69        assert (handle[dso]);
      70  
      71        fun_vec[dso] = (function) dlsym (handle[dso], "function");
      72        assert (fun_vec[dso]);
      73  
      74        pthread_mutex_unlock (&g_lock);
      75      }
      76  
      77    /* Spawn workers.  */
      78    pthread_t thread[DSO_EXEC_THREADS];
      79    int i, ret;
      80    uintptr_t result = 0;
      81    for (i = 0; i < DSO_EXEC_THREADS; i++)
      82      {
      83        pthread_mutex_lock (&g_lock);
      84        ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
      85        if (ret != 0)
      86  	{
      87  	  printf ("pthread_create failed: %d\n", ret);
      88  	  result = 1;
      89  	}
      90        pthread_mutex_unlock (&g_lock);
      91      }
      92  
      93    if (!result)
      94      for (i = 0; i < DSO_EXEC_THREADS; i++)
      95        {
      96  	ret = pthread_join (thread[i], NULL);
      97  	if (ret != 0)
      98  	  {
      99  	    printf ("pthread_join failed: %d\n", ret);
     100  	    result = 1;
     101  	  }
     102        }
     103  
     104    /* Close all DSOs.  */
     105    for (dso = 0; dso < DSO_SHARED_FILES; dso++)
     106      {
     107        pthread_mutex_lock (&g_lock);
     108        dlclose (handle[dso]);
     109        pthread_mutex_unlock (&g_lock);
     110      }
     111  
     112    /* Exit.  */
     113    pthread_exit ((void *) result);
     114  }
     115  
     116  static int
     117  do_test (void)
     118  {
     119    pthread_t thread[DSO_OPEN_THREADS];
     120    int i,j;
     121    int ret;
     122    int result = 0;
     123  
     124    pthread_mutex_init (&g_lock, NULL);
     125  
     126    /* 100 is arbitrary here and is known to trigger PR 13862.  */
     127    for (j = 0; j < 100; j++)
     128      {
     129        for (i = 0; i < DSO_OPEN_THREADS; i++)
     130  	{
     131  	  ret = pthread_create (&thread[i], NULL, dso_process,
     132  				(void *) (uintptr_t) i);
     133  	  if (ret != 0)
     134  	    {
     135  	      printf ("pthread_create failed: %d\n", ret);
     136  	      result = 1;
     137  	    }
     138  	}
     139  
     140        if (result)
     141  	break;
     142  
     143        for (i = 0; i < DSO_OPEN_THREADS; i++)
     144  	{
     145  	  ret = pthread_join (thread[i], NULL);
     146  	  if (ret != 0)
     147  	    {
     148  	      printf ("pthread_join failed: %d\n", ret);
     149  	      result = 1;
     150  	    }
     151  	}
     152      }
     153  
     154    return result;
     155  }
     156  
     157  #define TEST_FUNCTION do_test ()
     158  #define TIMEOUT 100
     159  #include "../test-skeleton.c"