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