Blame elf/tst-dlopen-nodelete-reloc.c

Packit Bot a917fd
/* Test interactions of dlopen, NODELETE, and relocations.
Packit Bot a917fd
   Copyright (C) 2019 Free Software Foundation, Inc.
Packit Bot a917fd
   This file is part of the GNU C Library.
Packit Bot a917fd
Packit Bot a917fd
   The GNU C Library is free software; you can redistribute it and/or
Packit Bot a917fd
   modify it under the terms of the GNU Lesser General Public
Packit Bot a917fd
   License as published by the Free Software Foundation; either
Packit Bot a917fd
   version 2.1 of the License, or (at your option) any later version.
Packit Bot a917fd
Packit Bot a917fd
   The GNU C Library is distributed in the hope that it will be useful,
Packit Bot a917fd
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot a917fd
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Bot a917fd
   Lesser General Public License for more details.
Packit Bot a917fd
Packit Bot a917fd
   You should have received a copy of the GNU Lesser General Public
Packit Bot a917fd
   License along with the GNU C Library; if not, see
Packit Bot a917fd
   <https://www.gnu.org/licenses/>.  */
Packit Bot a917fd
Packit Bot a917fd
/* This test exercises NODELETE propagation due to data relocations
Packit Bot a917fd
   and unique symbols, and the interaction with already-loaded
Packit Bot a917fd
   objects.  Some test objects are written in C++, to produce unique
Packit Bot a917fd
   symbol definitions.
Packit Bot a917fd
Packit Bot a917fd
   First test: Global scope variant, data relocation as the NODELETE
Packit Bot a917fd
   trigger.  mod1 is loaded first with a separate dlopen call.
Packit Bot a917fd
Packit Bot a917fd
      mod2 ---(may_finalize_mod1 relocation dependency)---> mod1
Packit Bot a917fd
    (NODELETE)                                   (marked as NODELETE)
Packit Bot a917fd
Packit Bot a917fd
   Second test: Local scope variant, data relocation.  mod3 is loaded
Packit Bot a917fd
   first, then mod5.
Packit Bot a917fd
Packit Bot a917fd
      mod5 ---(DT_NEEDED)--->  mod4  ---(DT_NEEDED)---> mod3
Packit Bot a917fd
    (NODELETE)           (not NODELETE)                  ^
Packit Bot a917fd
        \                                               / (marked as
Packit Bot a917fd
         `--(may_finalize_mod3 relocation dependency)--/   NODELETE)
Packit Bot a917fd
Packit Bot a917fd
   Third test: Shared local scope with unique symbol.  mod6 is loaded
Packit Bot a917fd
   first, then mod7.  No explicit dependencies between the two
Packit Bot a917fd
   objects, so first object has to be opened with RTLD_GLOBAL.
Packit Bot a917fd
Packit Bot a917fd
      mod7 ---(unique symbol)---> mod6
Packit Bot a917fd
                          (marked as NODELETE)
Packit Bot a917fd
Packit Bot a917fd
   Forth test: Non-shared scopes with unique symbol.  mod8 and mod10
Packit Bot a917fd
   are loaded from the main program.  mod8 loads mod9 from an ELF
Packit Bot a917fd
   constructor, mod10 loads mod11.  There are no DT_NEEDED
Packit Bot a917fd
   dependencies.  mod9 is promoted to the global scope form the main
Packit Bot a917fd
   program.  The unique symbol dependency is:
Packit Bot a917fd
Packit Bot a917fd
      mod9 ---(unique symbol)---> mod11
Packit Bot a917fd
                          (marked as NODELETE)
Packit Bot a917fd
Packit Bot a917fd
   Fifth test: Shared local scope with unique symbol, like test 3, but
Packit Bot a917fd
   this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL
Packit Bot a917fd
   needed):
Packit Bot a917fd
Packit Bot a917fd
                 DT_NEEDED
Packit Bot a917fd
      mod13 ---(unique symbol)---> mod12
Packit Bot a917fd
                          (marked as NODELETE)
Packit Bot a917fd
Packit Bot a917fd
   Sixth test: NODELETE status is retained after relocation failure
Packit Bot a917fd
   with unique symbol dependency.  The object graph ensures that the
Packit Bot a917fd
   unique symbol binding is processed before the dlopen failure.
Packit Bot a917fd
Packit Bot a917fd
                                        DT_NEEDED
Packit Bot a917fd
     mod17  --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14
Packit Bot a917fd
       \                       ^                  (RTLD_NODELETE)
Packit Bot a917fd
        \                 (DT_NEEDED)
Packit Bot a917fd
         \                     |
Packit Bot a917fd
          `---(DT_NEEDED)--> mod16
Packit Bot a917fd
                       (fails to relocate)
Packit Bot a917fd
Packit Bot a917fd
   mod14 is loaded first, and the loading mod17 is attempted.
Packit Bot a917fd
   mod14 must remain NODELETE after opening mod17 failed.  */
Packit Bot a917fd
Packit Bot a917fd
#include <stdio.h>
Packit Bot a917fd
#include <string.h>
Packit Bot a917fd
#include <stdbool.h>
Packit Bot a917fd
#include <support/check.h>
Packit Bot a917fd
#include <support/xdlfcn.h>
Packit Bot a917fd
Packit Bot a917fd
static int
Packit Bot a917fd
do_test (void)
Packit Bot a917fd
{
Packit Bot a917fd
  /* First case: global scope, regular data symbol.  Open the object
Packit Bot a917fd
     which is not NODELETE initially.  */
Packit Bot a917fd
  void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so",
Packit Bot a917fd
                        RTLD_NOW | RTLD_GLOBAL);
Packit Bot a917fd
  /* This is used to indicate that the ELF destructor may be
Packit Bot a917fd
     called.  */
Packit Bot a917fd
  bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1");
Packit Bot a917fd
  /* Open the NODELETE object.  */
Packit Bot a917fd
  void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW);
Packit Bot a917fd
  /* This has no effect because the DSO is directly marked as
Packit Bot a917fd
     NODELETE.  */
Packit Bot a917fd
  xdlclose (mod2);
Packit Bot a917fd
  /* This has no effect because the DSO has been indirectly marked as
Packit Bot a917fd
     NODELETE due to a relocation dependency.  */
Packit Bot a917fd
  xdlclose (mod1);
Packit Bot a917fd
Packit Bot a917fd
  /* Second case: local scope, regular data symbol.  Open the object
Packit Bot a917fd
     which is not NODELETE initially.  */
Packit Bot a917fd
  void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW);
Packit Bot a917fd
  bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3");
Packit Bot a917fd
  /* Open the NODELETE object.  */
Packit Bot a917fd
  void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW);
Packit Bot a917fd
  /* Again those have no effect because of NODELETE.  */
Packit Bot a917fd
  xdlclose (mod5);
Packit Bot a917fd
  xdlclose (mod3);
Packit Bot a917fd
Packit Bot a917fd
  /* Third case: Unique symbol.  */
Packit Bot a917fd
  void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so",
Packit Bot a917fd
                        RTLD_NOW | RTLD_GLOBAL);
Packit Bot a917fd
  bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6");
Packit Bot a917fd
  void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW);
Packit Bot a917fd
  bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7");
Packit Bot a917fd
  /* This should not have any effect because of the unique symbol and
Packit Bot a917fd
     the resulting NODELETE status.  */
Packit Bot a917fd
  xdlclose (mod6);
Packit Bot a917fd
  /* mod7 is not NODELETE and can be closed.  */
Packit Bot a917fd
  *may_finalize_mod7 = true;
Packit Bot a917fd
  xdlclose (mod7);
Packit Bot a917fd
Packit Bot a917fd
  /* Fourth case: Unique symbol, indirect loading.  */
Packit Bot a917fd
  void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW);
Packit Bot a917fd
  /* Also promote to global scope.  */
Packit Bot a917fd
  void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so",
Packit Bot a917fd
                        RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
Packit Bot a917fd
  bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9");
Packit Bot a917fd
  xdlclose (mod9);              /* Drop mod9 reference.  */
Packit Bot a917fd
  void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW);
Packit Bot a917fd
  void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so",
Packit Bot a917fd
                        RTLD_NOW | RTLD_NOLOAD);
Packit Bot a917fd
  bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11");
Packit Bot a917fd
  xdlclose (mod11);              /* Drop mod11 reference.  */
Packit Bot a917fd
  /* mod11 is not NODELETE and can be closed.  */
Packit Bot a917fd
  *may_finalize_mod11 = true;
Packit Bot a917fd
  /* Trigger closing of mod11, too.  */
Packit Bot a917fd
  xdlclose (mod10);
Packit Bot a917fd
  /* Does not trigger closing of mod9.  */
Packit Bot a917fd
  xdlclose (mod8);
Packit Bot a917fd
Packit Bot a917fd
  /* Fifth case: Unique symbol, with DT_NEEDED dependency.  */
Packit Bot a917fd
  void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW);
Packit Bot a917fd
  bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12");
Packit Bot a917fd
  void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW);
Packit Bot a917fd
  bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13");
Packit Bot a917fd
  /* This should not have any effect because of the unique symbol. */
Packit Bot a917fd
  xdlclose (mod12);
Packit Bot a917fd
  /* mod13 is not NODELETE and can be closed.  */
Packit Bot a917fd
  *may_finalize_mod13 = true;
Packit Bot a917fd
  xdlclose (mod13);
Packit Bot a917fd
Packit Bot a917fd
  /* Sixth case: Unique symbol binding must not cause loss of NODELETE
Packit Bot a917fd
     status.  */
Packit Bot a917fd
  void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so",
Packit Bot a917fd
                         RTLD_NOW | RTLD_NODELETE);
Packit Bot a917fd
  bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14");
Packit Bot a917fd
  TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW)
Packit Bot a917fd
               == NULL);
Packit Bot a917fd
  const char *message = dlerror ();
Packit Bot a917fd
  printf ("info: test 6 message: %s\n", message);
Packit Bot a917fd
  /* This must not close the object, it must still be NODELETE.  */
Packit Bot a917fd
  xdlclose (mod14);
Packit Bot a917fd
  xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD);
Packit Bot a917fd
Packit Bot a917fd
  /* Prepare for process exit.  Destructors for NODELETE objects will
Packit Bot a917fd
     be invoked.  */
Packit Bot a917fd
  *may_finalize_mod1 = true;
Packit Bot a917fd
  *may_finalize_mod3 = true;
Packit Bot a917fd
  *may_finalize_mod6 = true;
Packit Bot a917fd
  *may_finalize_mod9 = true;
Packit Bot a917fd
  *may_finalize_mod12 = true;
Packit Bot a917fd
  *may_finalize_mod14 = true;
Packit Bot a917fd
  return 0;
Packit Bot a917fd
}
Packit Bot a917fd
Packit Bot a917fd
#include <support/test-driver.c>