(root)/
glibc-2.38/
elf/
tst-tls20.c
       1  /* Test dtv setup if entries don't have monotone increasing generation.
       2     Copyright (C) 2021-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 <array_length.h>
      20  #include <dlfcn.h>
      21  #include <pthread.h>
      22  #include <stdbool.h>
      23  #include <stdint.h>
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <support/check.h>
      27  #include <support/support.h>
      28  #include <support/test-driver.h>
      29  #include <support/xdlfcn.h>
      30  #include <support/xthread.h>
      31  
      32  #define NMOD 100
      33  static void *mod[NMOD];
      34  
      35  static void
      36  load_fail (void)
      37  {
      38    /* Expected to fail because of a missing symbol.  */
      39    void *m = dlopen ("tst-tls20mod-bad.so", RTLD_NOW);
      40    if (m != NULL)
      41      FAIL_EXIT1 ("dlopen of tst-tls20mod-bad.so succeeded\n");
      42  }
      43  
      44  static void
      45  load_mod (int i)
      46  {
      47    char *buf = xasprintf ("tst-tls-manydynamic%02dmod.so", i);
      48    mod[i] = xdlopen (buf, RTLD_LAZY);
      49    free (buf);
      50  }
      51  
      52  static void
      53  unload_mod (int i)
      54  {
      55    if (mod[i] != NULL)
      56      xdlclose (mod[i]);
      57    mod[i] = NULL;
      58  }
      59  
      60  static void
      61  access (int i)
      62  {
      63    char *buf = xasprintf ("tls_global_%02d", i);
      64    dlerror ();
      65    int *p = dlsym (mod[i], buf);
      66    if (test_verbose)
      67      printf ("mod[%d]: &tls = %p\n", i, p);
      68    if (p == NULL)
      69      FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
      70    TEST_COMPARE (*p, 0);
      71    ++*p;
      72    free (buf);
      73  }
      74  
      75  static void
      76  access_mod (const char *modname, void *mod, int i)
      77  {
      78    char *modsym = xasprintf ("tls_global_%d", i);
      79    dlerror ();
      80    int *p = dlsym (mod, modsym);
      81    if (test_verbose)
      82      printf ("%s: &tls = %p\n", modname, p);
      83    if (p == NULL)
      84      FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
      85    TEST_COMPARE (*p, 0);
      86    ++*p;
      87    free (modsym);
      88  }
      89  
      90  static void
      91  access_dep (int i)
      92  {
      93    char *modname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", i);
      94    void *moddep = xdlopen (modname, RTLD_LAZY);
      95    access_mod (modname, moddep, i);
      96    free (modname);
      97    xdlclose (moddep);
      98  }
      99  
     100  struct start_args
     101  {
     102    const char *modname;
     103    void *mod;
     104    int modi;
     105    int ndeps;
     106    const int *deps;
     107  };
     108  
     109  static void *
     110  start (void *a)
     111  {
     112    struct start_args *args = a;
     113  
     114    for (int i = 0; i < NMOD; i++)
     115      if (mod[i] != NULL)
     116        access (i);
     117  
     118    if (args != NULL)
     119      {
     120        access_mod (args->modname, args->mod, args->modi);
     121        for (int n = 0; n < args->ndeps; n++)
     122  	access_dep (args->deps[n]);
     123      }
     124  
     125    return 0;
     126  }
     127  
     128  /* This test gaps with shared libraries with dynamic TLS that has no
     129     dependencies.  The DTV gap is set with by trying to load an invalid
     130     module, the entry should be used on the dlopen.  */
     131  static void
     132  do_test_no_depedency (void)
     133  {
     134    for (int i = 0; i < NMOD; i++)
     135      {
     136        load_mod (i);
     137        /* Bump the generation of mod[0] without using new dtv slot.  */
     138        unload_mod (0);
     139        load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135.  */
     140        load_mod (0);
     141        /* Access TLS in all loaded modules.  */
     142        pthread_t t = xpthread_create (0, start, 0);
     143        xpthread_join (t);
     144      }
     145    for (int i = 0; i < NMOD; i++)
     146      unload_mod (i);
     147  }
     148  
     149  /* The following test check DTV gaps handling with shared libraries that has
     150     dependencies.  It defines 5 different sets:
     151  
     152     1. Single dependency:
     153        mod0 -> mod1
     154     2. Double dependency:
     155        mod2 -> [mod3,mod4]
     156     3. Double dependency with each dependency dependent of another module:
     157        mod5 -> [mod6,mod7] -> mod8
     158     4. Long chain with one double dependency in the middle:
     159        mod9 -> [mod10, mod11] -> mod12 -> mod13
     160     5. Long chain with two double dependencies in the middle:
     161        mod14 -> mod15 -> [mod16, mod17]
     162        mod15 -> [mod18, mod19]
     163  
     164     This does not cover all the possible gaps and configuration, but it
     165     should check if different dynamic shared sets are placed correctly in
     166     different gaps configurations.  */
     167  
     168  static int
     169  nmodules (uint32_t v)
     170  {
     171    unsigned int r = 0;
     172    while (v >>= 1)
     173      r++;
     174    return r + 1;
     175  }
     176  
     177  static inline bool
     178  is_mod_set (uint32_t g, uint32_t n)
     179  {
     180    return (1U << (n - 1)) & g;
     181  }
     182  
     183  static void
     184  print_gap (uint32_t g)
     185  {
     186    if (!test_verbose)
     187      return;
     188    printf ("gap: ");
     189    int nmods = nmodules (g);
     190    for (int n = 1; n <= nmods; n++)
     191      printf ("%c", ((1 << (n - 1)) & g) == 0 ? 'G' : 'M');
     192    printf ("\n");
     193  }
     194  
     195  static void
     196  do_test_dependency (void)
     197  {
     198    /* Maps the module and its dependencies, use thread to access the TLS on
     199       each loaded module.  */
     200    static const int tlsmanydeps0[] = { 1 };
     201    static const int tlsmanydeps1[] = { 3, 4 };
     202    static const int tlsmanydeps2[] = { 6, 7, 8 };
     203    static const int tlsmanydeps3[] = { 10, 11, 12 };
     204    static const int tlsmanydeps4[] = { 15, 16, 17, 18, 19 };
     205    static const struct tlsmanydeps_t
     206    {
     207      int modi;
     208      int ndeps;
     209      const int *deps;
     210    } tlsmanydeps[] =
     211    {
     212      {  0, array_length (tlsmanydeps0), tlsmanydeps0 },
     213      {  2, array_length (tlsmanydeps1), tlsmanydeps1 },
     214      {  5, array_length (tlsmanydeps2), tlsmanydeps2 },
     215      {  9, array_length (tlsmanydeps3), tlsmanydeps3 },
     216      { 14, array_length (tlsmanydeps4), tlsmanydeps4 },
     217    };
     218  
     219    /* The gap configuration is defined as a bitmap: the bit set represents a
     220       loaded module prior the tests execution, while a bit unset is a module
     221       unloaded.  Not all permtation will show gaps, but it is simpler than
     222       define each one independently.  */
     223    for (uint32_t g = 0; g < 64; g++)
     224      {
     225        print_gap (g);
     226        int nmods = nmodules (g);
     227  
     228        int mods[nmods];
     229        /* We use '0' as indication for a gap, to avoid the dlclose on iteration
     230  	 cleanup.  */
     231        for (int n = 1; n < nmods; n++)
     232  	{
     233  	  load_mod (n);
     234  	   mods[n] = n;
     235  	}
     236        for (int n = 1; n < nmods; n++)
     237  	{
     238  	  if (!is_mod_set (g, n))
     239  	    {
     240  	      unload_mod (n);
     241  	      mods[n] = 0;
     242  	    }
     243  	}
     244  
     245        for (int t = 0; t < array_length (tlsmanydeps); t++)
     246  	{
     247  	  char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep.so",
     248  					tlsmanydeps[t].modi);
     249  	  void *moddep = xdlopen (moddepname, RTLD_LAZY);
     250  
     251  	  /* Access TLS in all loaded modules.  */
     252  	  struct start_args args =
     253  	    {
     254  	      moddepname,
     255  	      moddep,
     256  	      tlsmanydeps[t].modi,
     257  	      tlsmanydeps[t].ndeps,
     258  	      tlsmanydeps[t].deps
     259  	    };
     260  	  pthread_t t = xpthread_create (0, start, &args);
     261  	  xpthread_join (t);
     262  
     263  	  free (moddepname);
     264  	  xdlclose (moddep);
     265  	}
     266  
     267        for (int n = 1; n < nmods; n++)
     268  	if (mods[n] != 0)
     269  	  unload_mod (n);
     270      }
     271  }
     272  
     273  /* The following test check DTV gaps handling with shared libraries that has
     274     invalid dependencies.  It defines 5 different sets:
     275  
     276     1. Single dependency:
     277        mod0 -> invalid
     278     2. Double dependency:
     279        mod1 -> [mod2,invalid]
     280     3. Double dependency with each dependency dependent of another module:
     281        mod3 -> [mod4,mod5] -> invalid
     282     4. Long chain with one double dependency in the middle:
     283        mod6 -> [mod7, mod8] -> mod12 -> invalid
     284     5. Long chain with two double dependencies in the middle:
     285        mod10 -> mod11 -> [mod12, mod13]
     286        mod12 -> [mod14, invalid]
     287  
     288     This does not cover all the possible gaps and configuration, but it
     289     should check if different dynamic shared sets are placed correctly in
     290     different gaps configurations.  */
     291  
     292  static void
     293  do_test_invalid_dependency (bool bind_now)
     294  {
     295    static const int tlsmanydeps[] = { 0, 1, 3, 6, 10 };
     296  
     297    /* The gap configuration is defined as a bitmap: the bit set represents a
     298       loaded module prior the tests execution, while a bit unset is a module
     299       unloaded.  Not all permtation will show gaps, but it is simpler than
     300       define each one independently.  */
     301    for (uint32_t g = 0; g < 64; g++)
     302      {
     303        print_gap (g);
     304        int nmods = nmodules (g);
     305  
     306        int mods[nmods];
     307        /* We use '0' as indication for a gap, to avoid the dlclose on iteration
     308  	 cleanup.  */
     309        for (int n = 1; n < nmods; n++)
     310  	{
     311  	  load_mod (n);
     312  	   mods[n] = n;
     313  	}
     314        for (int n = 1; n < nmods; n++)
     315  	{
     316  	  if (!is_mod_set (g, n))
     317  	    {
     318  	      unload_mod (n);
     319  	      mods[n] = 0;
     320  	    }
     321  	}
     322  
     323        for (int t = 0; t < array_length (tlsmanydeps); t++)
     324  	{
     325  	  char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep-bad.so",
     326  					tlsmanydeps[t]);
     327  	  void *moddep;
     328  	  if (bind_now)
     329  	    {
     330  	      moddep = dlopen (moddepname, RTLD_NOW);
     331  	      TEST_VERIFY (moddep == 0);
     332  	    }
     333  	  else
     334  	    moddep = dlopen (moddepname, RTLD_LAZY);
     335  
     336  	  /* Access TLS in all loaded modules.  */
     337  	  pthread_t t = xpthread_create (0, start, NULL);
     338  	  xpthread_join (t);
     339  
     340  	  free (moddepname);
     341  	  if (!bind_now)
     342  	    xdlclose (moddep);
     343  	}
     344  
     345        for (int n = 1; n < nmods; n++)
     346  	if (mods[n] != 0)
     347  	  unload_mod (n);
     348      }
     349  }
     350  
     351  static int
     352  do_test (void)
     353  {
     354    do_test_no_depedency ();
     355    do_test_dependency ();
     356    do_test_invalid_dependency (true);
     357    do_test_invalid_dependency (false);
     358  
     359    return 0;
     360  }
     361  
     362  #include <support/test-driver.c>