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

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