[PATCH 3/8] elf: Avoid redundant ld.so.cache reload after first load

Adhemerval Zanella <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
_dl_check_ldsocache_needs_loading only stored the stat fields it
compares (mtime, ino, size, dev) on the path where a cache was already
loaded.  On the very first call CACHE is NULL and the function returned
"needs loading" without recording those fields, leaving
new_cache_file_time zero.  The next call then copied that zero value
into cache_file_time and compared it against the freshly stat'd values,
which always differed, forcing a second, unnecessary load (munmap +
mmap + re-parse) of an unchanged cache at every startup.

It can be shown with repro:

  $ cat << EOF > repro.c
  #include <dlfcn.h>
  int main (void) { dlopen ("does-not-exist-xyz.so.99", RTLD_NOW); return 0; }
  EOF
  $ gcc repro.c -o repro
  $ strace -f -e trace=openat elf/ld.so --library-path . ./repro 2>&1 | grep -c "/etc/ld.so.cache"

The result should be 1, instead of 2.

Record the stat fields as soon as the stat succeeds, before the
CACHE == NULL early return, so the following call has an accurate
baseline and does not spuriously reload.
---
 elf/dl-cache.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 498196d0aa3..03bcd5bd06e 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -433,17 +433,20 @@ _dl_check_ldsocache_needs_loading (void)
   if (rv < 0)
     return false;
 
-  /* Any file is better than no file (likely the first time
-     through).  */
-  if (cache == NULL)
-    return true;
-
-  /* Store the fields we check, in order they're likely to differ.  */
+  /* Store the fields we check, in order they're likely to differ.  We
+     must do this even for the first load (CACHE == NULL below), so that
+     the next call copies an accurate NEW_CACHE_FILE_TIME into
+     CACHE_FILE_TIME and does not spuriously reload the unchanged cache.  */
   new_cache_file_time.mtime = new_cache_file_stat.st_mtime;
   new_cache_file_time.ino = new_cache_file_stat.st_ino;
   new_cache_file_time.size = new_cache_file_stat.st_size;
   new_cache_file_time.dev = new_cache_file_stat.st_dev;
 
+  /* Any file is better than no file (likely the first time
+     through).  */
+  if (cache == NULL)
+    return true;
+
   /* At this point, NEW_CACHE_FILE_TIME is valid as well as
      CACHE_FILE_TIME, so we compare them.  */
   return (memcmp (&new_cache_file_time, &cache_file_time,
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.