(root)/
glibc-2.38/
elf/
tst-dl_find_object-threads.c
       1  /* _dl_find_object test with parallelism.
       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     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <array_length.h>
      20  #include <dlfcn.h>
      21  #include <elf/dl-find_object.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <support/check.h>
      25  #include <support/support.h>
      26  #include <support/xdlfcn.h>
      27  #include <support/xthread.h>
      28  #include <support/xunistd.h>
      29  
      30  /* Computes the expected _dl_find_object result directly from the
      31     map.  */
      32  static void
      33  from_map (struct link_map *l, struct dl_find_object *expected)
      34  {
      35    struct dl_find_object_internal internal;
      36    _dl_find_object_from_map (l, &internal);
      37    _dl_find_object_to_external (&internal, expected);
      38  }
      39  
      40  /* Returns the soname for the test object NUMBER.  */
      41  static char *
      42  soname (int number)
      43  {
      44    return xasprintf ("tst-dl_find_object-mod%d.so", number);
      45  }
      46  
      47  /* Returns the data symbol name for the test object NUMBER.  */
      48  static char *
      49  symbol (int number)
      50  {
      51    return xasprintf ("mod%d_data", number);
      52  }
      53  
      54  struct verify_data
      55  {
      56    char *soname;
      57    void *address;                /* Address in the shared object.  */
      58    struct dl_find_object dlfo;
      59    pthread_t thr;
      60  };
      61  
      62  /* Compare _dl_find_object result at ADDRESS with *EXPECTED.  */
      63  static void
      64  check (void *address, struct dl_find_object *expected, int line)
      65  {
      66    struct dl_find_object actual;
      67    int ret = _dl_find_object (address, &actual);
      68    if (expected == NULL)
      69      {
      70        if (ret != -1)
      71          {
      72            support_record_failure ();
      73            printf ("%s:%d: unexpected success for %p\n",
      74                    __FILE__, line, address);
      75          }
      76        return;
      77      }
      78    if (ret != 0)
      79      {
      80        support_record_failure ();
      81        printf ("%s:%d: unexpected failure for %p\n",
      82                __FILE__, line, address);
      83        return;
      84      }
      85  
      86    if (actual.dlfo_flags != expected->dlfo_flags)
      87      {
      88        support_record_failure ();
      89        printf ("%s:%d: error: %p: flags is %llu, expected %llu\n",
      90                __FILE__, line, address,
      91                actual.dlfo_flags, expected->dlfo_flags);
      92      }
      93    if (actual.dlfo_flags != expected->dlfo_flags)
      94      {
      95        support_record_failure ();
      96        printf ("%s:%d: error: %p: map start is %p, expected %p\n",
      97                __FILE__, line,
      98                address, actual.dlfo_map_start, expected->dlfo_map_start);
      99      }
     100    if (actual.dlfo_map_end != expected->dlfo_map_end)
     101      {
     102        support_record_failure ();
     103        printf ("%s:%d: error: %p: map end is %p, expected %p\n",
     104                __FILE__, line,
     105                address, actual.dlfo_map_end, expected->dlfo_map_end);
     106      }
     107    if (actual.dlfo_link_map != expected->dlfo_link_map)
     108      {
     109        support_record_failure ();
     110        printf ("%s:%d: error: %p: link map is %p, expected %p\n",
     111                __FILE__, line,
     112                address, actual.dlfo_link_map, expected->dlfo_link_map);
     113      }
     114    if (actual.dlfo_eh_frame != expected->dlfo_eh_frame)
     115      {
     116        support_record_failure ();
     117        printf ("%s:%d: error: %p: EH frame is %p, expected %p\n",
     118                __FILE__, line,
     119                address, actual.dlfo_eh_frame, expected->dlfo_eh_frame);
     120      }
     121  #if DLFO_STRUCT_HAS_EH_DBASE
     122    if (actual.dlfo_eh_dbase != expected->dlfo_eh_dbase)
     123      {
     124        support_record_failure ();
     125        printf ("%s:%d: error: %p: data base is %p, expected %p\n",
     126                __FILE__, line,
     127                address, actual.dlfo_eh_dbase, expected->dlfo_eh_dbase);
     128      }
     129  #endif
     130  #if DLFO_STRUCT_HAS_EH_COUNT
     131    if (actual.dlfo_eh_count != expected->dlfo_eh_count)
     132      {
     133        support_record_failure ();
     134        printf ("%s:%d: error: %p: count is %d, expected %d\n",
     135                __FILE__, line,
     136                address, actual.dlfo_eh_count, expected->dlfo_eh_count);
     137      }
     138  #endif
     139  }
     140  
     141  /* Request process termination after 0.3 seconds.  */
     142  static bool exit_requested;
     143  static void *
     144  exit_thread (void *ignored)
     145  {
     146    usleep (300 * 1000);
     147    __atomic_store_n (&exit_requested, true,  __ATOMIC_RELAXED);
     148    return NULL;
     149  }
     150  
     151  static void *
     152  verify_thread (void *closure)
     153  {
     154    struct verify_data *data = closure;
     155  
     156    while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
     157      {
     158        check (data->address, &data->dlfo, __LINE__);
     159        check (data->dlfo.dlfo_map_start, &data->dlfo, __LINE__);
     160        check (data->dlfo.dlfo_map_end - 1, &data->dlfo, __LINE__);
     161      }
     162  
     163    return NULL;
     164  }
     165  
     166  /* Sets up the verification data, dlopen'ing shared object NUMBER, and
     167     launches a verification thread.  */
     168  static void
     169  start_verify (int number, struct verify_data *data)
     170  {
     171    data->soname = soname (number);
     172    struct link_map *l = xdlopen (data->soname, RTLD_NOW);
     173    from_map (l, &data->dlfo);
     174    TEST_VERIFY_EXIT (data->dlfo.dlfo_link_map == l);
     175    char *sym = symbol (number);
     176    data->address = xdlsym (data->dlfo.dlfo_link_map, sym);
     177    free (sym);
     178    data->thr = xpthread_create (NULL, verify_thread, data);
     179  }
     180  
     181  
     182  static int
     183  do_test (void)
     184  {
     185    struct verify_data data_mod2;
     186    struct verify_data data_mod4;
     187    struct verify_data data_mod7;
     188  
     189    /* Load the modules with gaps.  */
     190    {
     191      void *mod1 = xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW);
     192      start_verify (2, &data_mod2);
     193      void *mod3 = xdlopen ("tst-dl_find_object-mod3.so", RTLD_NOW);
     194      start_verify (4, &data_mod4);
     195      void *mod5 = xdlopen ("tst-dl_find_object-mod5.so", RTLD_NOW);
     196      void *mod6 = xdlopen ("tst-dl_find_object-mod6.so", RTLD_NOW);
     197      start_verify (7, &data_mod7);
     198      xdlclose (mod6);
     199      xdlclose (mod5);
     200      xdlclose (mod3);
     201      xdlclose (mod1);
     202    }
     203  
     204    /* Objects that continuously opened and closed.  */
     205    struct temp_object
     206    {
     207      char *soname;
     208      char *symbol;
     209      struct link_map *link_map;
     210      void *address;
     211    } temp_objects[] =
     212      {
     213        { soname (1), symbol (1), },
     214        { soname (3), symbol (3), },
     215        { soname (5), symbol (5), },
     216        { soname (6), symbol (6), },
     217        { soname (8), symbol (8), },
     218        { soname (9), symbol (9), },
     219      };
     220  
     221    pthread_t exit_thr = xpthread_create (NULL, exit_thread, NULL);
     222  
     223    struct drand48_data state;
     224    srand48_r (1, &state);
     225    while (!__atomic_load_n (&exit_requested, __ATOMIC_RELAXED))
     226      {
     227        long int idx;
     228        lrand48_r (&state, &idx);
     229        idx %= array_length (temp_objects);
     230        if (temp_objects[idx].link_map == NULL)
     231          {
     232            temp_objects[idx].link_map = xdlopen (temp_objects[idx].soname,
     233                                                  RTLD_NOW);
     234            temp_objects[idx].address = xdlsym (temp_objects[idx].link_map,
     235                                                temp_objects[idx].symbol);
     236          }
     237        else
     238          {
     239            xdlclose (temp_objects[idx].link_map);
     240            temp_objects[idx].link_map = NULL;
     241            struct dl_find_object dlfo;
     242            int ret = _dl_find_object (temp_objects[idx].address, &dlfo);
     243            if (ret != -1)
     244              {
     245                TEST_VERIFY_EXIT (ret == 0);
     246                support_record_failure ();
     247                printf ("%s: error: %s EH found after dlclose, link map %p\n",
     248                        __FILE__, temp_objects[idx].soname, dlfo.dlfo_link_map);
     249              }
     250          }
     251      }
     252  
     253    xpthread_join (data_mod2.thr);
     254    xpthread_join (data_mod4.thr);
     255    xpthread_join (data_mod7.thr);
     256    xpthread_join (exit_thr);
     257  
     258    for (size_t i = 0; i < array_length (temp_objects); ++i)
     259      {
     260        free (temp_objects[i].soname);
     261        free (temp_objects[i].symbol);
     262        if (temp_objects[i].link_map != NULL)
     263          xdlclose (temp_objects[i].link_map);
     264      }
     265  
     266    free (data_mod2.soname);
     267    free (data_mod4.soname);
     268    xdlclose (data_mod4.dlfo.dlfo_link_map);
     269    free (data_mod7.soname);
     270    xdlclose (data_mod7.dlfo.dlfo_link_map);
     271  
     272    return 0;
     273  }
     274  
     275  #include <support/test-driver.c>