mirror of https://gitee.com/Nocallback/glibc.git
Browse Source
This recognizes the DL_CACHE_HWCAP_EXTENSION flag in cache entries, and picks the supported cache entry with the highest priority. The elf/tst-glibc-hwcaps-prepend-cache test documents a non-desired aspect of the current cache implementation: If the cache selects a DSO that does not exist on disk, _dl_map_object falls back to open_path, which may or may not find an alternative implementation. This is an existing limitation that also applies to the legacy hwcaps processing for ld.so.cache. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>rearnsha/mte-v4.0
10 changed files with 508 additions and 3 deletions
@ -0,0 +1,45 @@ |
|||
/* Wrapper to invoke tst-glibc-hwcaps in a container, to test ld.so.cache.
|
|||
Copyright (C) 2020 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
/* This program is just a wrapper that runs ldconfig followed by
|
|||
tst-glibc-hwcaps. The actual test is provided via an |
|||
implementation in a sysdeps subdirectory. */ |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <support/support.h> |
|||
#include <unistd.h> |
|||
|
|||
int |
|||
main (int argc, char **argv) |
|||
{ |
|||
/* Run ldconfig to populate the cache. */ |
|||
{ |
|||
char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); |
|||
if (system (command) != 0) |
|||
return 1; |
|||
free (command); |
|||
} |
|||
|
|||
/* Reuse tst-glibc-hwcaps. Since this code is running in a
|
|||
container, we can launch it directly. */ |
|||
char *path = xasprintf ("%s/elf/tst-glibc-hwcaps", support_objdir_root); |
|||
execv (path, argv); |
|||
printf ("error: execv of %s failed: %m\n", path); |
|||
return 1; |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
# This file was created to suppress a warning from ldconfig: |
|||
# /sbin/ldconfig: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf: No such file or directory |
|||
@ -0,0 +1,6 @@ |
|||
# test-container does not support scripts in sysdeps directories, so |
|||
# collect everything in one file. |
|||
|
|||
cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so |
|||
cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so |
|||
cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so |
|||
@ -0,0 +1,149 @@ |
|||
/* Test that --glibc-hwcaps-prepend works, using dlopen and /etc/ld.so.cache.
|
|||
Copyright (C) 2020 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<https://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <dlfcn.h> |
|||
#include <stddef.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <support/check.h> |
|||
#include <support/support.h> |
|||
#include <support/xdlfcn.h> |
|||
#include <support/xunistd.h> |
|||
|
|||
/* Invoke /sbin/ldconfig with some error checking. */ |
|||
static void |
|||
run_ldconfig (void) |
|||
{ |
|||
char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); |
|||
TEST_COMPARE (system (command), 0); |
|||
free (command); |
|||
} |
|||
|
|||
/* The library under test. */ |
|||
#define SONAME "libmarkermod1.so" |
|||
|
|||
static int |
|||
do_test (void) |
|||
{ |
|||
if (dlopen (SONAME, RTLD_NOW) != NULL) |
|||
FAIL_EXIT1 (SONAME " is already on the search path"); |
|||
|
|||
/* Install the default implementation of libmarkermod1.so. */ |
|||
xmkdirp ("/etc", 0777); |
|||
support_write_file_string ("/etc/ld.so.conf", "/glibc-test/lib\n"); |
|||
xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend2", 0777); |
|||
xmkdirp ("/glibc-test/lib/glibc-hwcaps/prepend3", 0777); |
|||
{ |
|||
char *src = xasprintf ("%s/elf/libmarkermod1-1.so", support_objdir_root); |
|||
support_copy_file (src, "/glibc-test/lib/" SONAME); |
|||
free (src); |
|||
} |
|||
run_ldconfig (); |
|||
{ |
|||
/* The default implementation can now be loaded. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 1); |
|||
xdlclose (handle); |
|||
} |
|||
|
|||
/* Add the first override to the directory that is searched last. */ |
|||
{ |
|||
char *src = xasprintf ("%s/elf/libmarkermod1-2.so", support_objdir_root); |
|||
support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend2/" |
|||
SONAME); |
|||
free (src); |
|||
} |
|||
{ |
|||
/* This is still the first implementation. The cache has not been
|
|||
updated. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 1); |
|||
xdlclose (handle); |
|||
} |
|||
run_ldconfig (); |
|||
{ |
|||
/* After running ldconfig, it is the second implementation. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 2); |
|||
xdlclose (handle); |
|||
} |
|||
|
|||
/* Add the second override to the directory that is searched first. */ |
|||
{ |
|||
char *src = xasprintf ("%s/elf/libmarkermod1-3.so", support_objdir_root); |
|||
support_copy_file (src, "/glibc-test/lib/glibc-hwcaps/prepend3/" |
|||
SONAME); |
|||
free (src); |
|||
} |
|||
{ |
|||
/* This is still the second implementation. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 2); |
|||
xdlclose (handle); |
|||
} |
|||
run_ldconfig (); |
|||
{ |
|||
/* After running ldconfig, it is the third implementation. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 3); |
|||
xdlclose (handle); |
|||
} |
|||
|
|||
/* Remove the second override again, without running ldconfig.
|
|||
Ideally, this would revert to implementation 2. However, in the |
|||
current implementation, the cache returns exactly one file name |
|||
which does not exist after unlinking, so the dlopen fails. */ |
|||
xunlink ("/glibc-test/lib/glibc-hwcaps/prepend3/" SONAME); |
|||
TEST_VERIFY (dlopen (SONAME, RTLD_NOW) == NULL); |
|||
run_ldconfig (); |
|||
{ |
|||
/* After running ldconfig, the second implementation is available
|
|||
once more. */ |
|||
void *handle = xdlopen (SONAME, RTLD_NOW); |
|||
int (*marker1) (void) = xdlsym (handle, "marker1"); |
|||
TEST_COMPARE (marker1 (), 2); |
|||
xdlclose (handle); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void |
|||
prepare (int argc, char **argv) |
|||
{ |
|||
const char *no_restart = "no-restart"; |
|||
if (argc == 2 && strcmp (argv[1], no_restart) == 0) |
|||
return; |
|||
/* Re-execute the test with an explicit loader invocation. */ |
|||
execl (support_objdir_elf_ldso, |
|||
support_objdir_elf_ldso, |
|||
"--glibc-hwcaps-prepend", "prepend3:prepend2", |
|||
argv[0], no_restart, |
|||
NULL); |
|||
printf ("error: execv of %s failed: %m\n", argv[0]); |
|||
_exit (1); |
|||
} |
|||
|
|||
#define PREPARE prepare |
|||
#include <support/test-driver.c> |
|||
Loading…
Reference in new issue