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

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