(root)/
glibc-2.38/
elf/
tst-dlopen-nodelete-reloc.c
       1  /* Test interactions of dlopen, NODELETE, and relocations.
       2     Copyright (C) 2019-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 test exercises NODELETE propagation due to data relocations
      20     and unique symbols, and the interaction with already-loaded
      21     objects.  Some test objects are written in C++, to produce unique
      22     symbol definitions.
      23  
      24     First test: Global scope variant, data relocation as the NODELETE
      25     trigger.  mod1 is loaded first with a separate dlopen call.
      26  
      27        mod2 ---(may_finalize_mod1 relocation dependency)---> mod1
      28      (NODELETE)                                   (marked as NODELETE)
      29  
      30     Second test: Local scope variant, data relocation.  mod3 is loaded
      31     first, then mod5.
      32  
      33        mod5 ---(DT_NEEDED)--->  mod4  ---(DT_NEEDED)---> mod3
      34      (NODELETE)           (not NODELETE)                  ^
      35          \                                               / (marked as
      36           `--(may_finalize_mod3 relocation dependency)--/   NODELETE)
      37  
      38     Third test: Shared local scope with unique symbol.  mod6 is loaded
      39     first, then mod7.  No explicit dependencies between the two
      40     objects, so first object has to be opened with RTLD_GLOBAL.
      41  
      42        mod7 ---(unique symbol)---> mod6
      43                            (marked as NODELETE)
      44  
      45     Forth test: Non-shared scopes with unique symbol.  mod8 and mod10
      46     are loaded from the main program.  mod8 loads mod9 from an ELF
      47     constructor, mod10 loads mod11.  There are no DT_NEEDED
      48     dependencies.  mod9 is promoted to the global scope form the main
      49     program.  The unique symbol dependency is:
      50  
      51        mod9 ---(unique symbol)---> mod11
      52                            (marked as NODELETE)
      53  
      54     Fifth test: Shared local scope with unique symbol, like test 3, but
      55     this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL
      56     needed):
      57  
      58                   DT_NEEDED
      59        mod13 ---(unique symbol)---> mod12
      60                            (marked as NODELETE)
      61  
      62     Sixth test: NODELETE status is retained after relocation failure
      63     with unique symbol dependency.  The object graph ensures that the
      64     unique symbol binding is processed before the dlopen failure.
      65  
      66                                          DT_NEEDED
      67       mod17  --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14
      68         \                       ^                  (RTLD_NODELETE)
      69          \                 (DT_NEEDED)
      70           \                     |
      71            `---(DT_NEEDED)--> mod16
      72                         (fails to relocate)
      73  
      74     mod14 is loaded first, and the loading mod17 is attempted.
      75     mod14 must remain NODELETE after opening mod17 failed.  */
      76  
      77  #include <stdio.h>
      78  #include <string.h>
      79  #include <stdbool.h>
      80  #include <support/check.h>
      81  #include <support/xdlfcn.h>
      82  
      83  static int
      84  do_test (void)
      85  {
      86    /* First case: global scope, regular data symbol.  Open the object
      87       which is not NODELETE initially.  */
      88    void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so",
      89                          RTLD_NOW | RTLD_GLOBAL);
      90    /* This is used to indicate that the ELF destructor may be
      91       called.  */
      92    bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1");
      93    /* Open the NODELETE object.  */
      94    void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW);
      95    /* This has no effect because the DSO is directly marked as
      96       NODELETE.  */
      97    xdlclose (mod2);
      98    /* This has no effect because the DSO has been indirectly marked as
      99       NODELETE due to a relocation dependency.  */
     100    xdlclose (mod1);
     101  
     102    /* Second case: local scope, regular data symbol.  Open the object
     103       which is not NODELETE initially.  */
     104    void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW);
     105    bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3");
     106    /* Open the NODELETE object.  */
     107    void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW);
     108    /* Again those have no effect because of NODELETE.  */
     109    xdlclose (mod5);
     110    xdlclose (mod3);
     111  
     112    /* Third case: Unique symbol.  */
     113    void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so",
     114                          RTLD_NOW | RTLD_GLOBAL);
     115    bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6");
     116    void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW);
     117    bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7");
     118    /* This should not have any effect because of the unique symbol and
     119       the resulting NODELETE status.  */
     120    xdlclose (mod6);
     121    /* mod7 is not NODELETE and can be closed.  */
     122    *may_finalize_mod7 = true;
     123    xdlclose (mod7);
     124  
     125    /* Fourth case: Unique symbol, indirect loading.  */
     126    void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW);
     127    /* Also promote to global scope.  */
     128    void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so",
     129                          RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
     130    bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9");
     131    xdlclose (mod9);              /* Drop mod9 reference.  */
     132    void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW);
     133    void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so",
     134                          RTLD_NOW | RTLD_NOLOAD);
     135    bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11");
     136    xdlclose (mod11);              /* Drop mod11 reference.  */
     137    /* mod11 is not NODELETE and can be closed.  */
     138    *may_finalize_mod11 = true;
     139    /* Trigger closing of mod11, too.  */
     140    xdlclose (mod10);
     141    /* Does not trigger closing of mod9.  */
     142    xdlclose (mod8);
     143  
     144    /* Fifth case: Unique symbol, with DT_NEEDED dependency.  */
     145    void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW);
     146    bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12");
     147    void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW);
     148    bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13");
     149    /* This should not have any effect because of the unique symbol. */
     150    xdlclose (mod12);
     151    /* mod13 is not NODELETE and can be closed.  */
     152    *may_finalize_mod13 = true;
     153    xdlclose (mod13);
     154  
     155    /* Sixth case: Unique symbol binding must not cause loss of NODELETE
     156       status.  */
     157    void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so",
     158                           RTLD_NOW | RTLD_NODELETE);
     159    bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14");
     160    TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW)
     161                 == NULL);
     162    const char *message = dlerror ();
     163    printf ("info: test 6 message: %s\n", message);
     164    /* This must not close the object, it must still be NODELETE.  */
     165    xdlclose (mod14);
     166    xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD);
     167  
     168    /* Prepare for process exit.  Destructors for NODELETE objects will
     169       be invoked.  */
     170    *may_finalize_mod1 = true;
     171    *may_finalize_mod3 = true;
     172    *may_finalize_mod6 = true;
     173    *may_finalize_mod9 = true;
     174    *may_finalize_mod12 = true;
     175    *may_finalize_mod14 = true;
     176    return 0;
     177  }
     178  
     179  #include <support/test-driver.c>