From faf3daa961463a80e453af13ddab50f1bae2c8ca Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 18 Sep 2019 13:03:36 +0100
Subject: [PATCH] WIP: capture-libs: Treat unversioned libraries as in
 indeterminate order

On at least Debian, Ubuntu and Manjaro, libgcc_s.so.1 is a regular
file, not a symlink to a versioned name (libgcc_s.so.1.2.3) like most
shared libraries. However, on Fedora 30 it is a symlink to a versioned
name like libgcc_s-9-20190827.so.1.

This can cause problems if a Debian-derived container is used on a Fedora
host, with host graphics drivers.

TODO: it isn't clear whether this change makes any practical difference,
because strverscmp("libgcc_s.so.1", "libgcc_s-9-20190827.so.1") == 0
anyway.
---
 utils/capture-libs.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/utils/capture-libs.c b/utils/capture-libs.c
index f2e2d28c3..156603403 100644
--- a/utils/capture-libs.c
+++ b/utils/capture-libs.c
@@ -356,6 +356,41 @@ library_cmp_by_name( const char *soname,
          "\"%s\" from \"%s\"",
          soname, left_basename, left_from, right_basename, right_from );
 
+  if( strcmp( left_basename, right_basename ) == 0 )
+  {
+    DEBUG( DEBUG_TOOL,
+           "Name of %s \"%s\" from \"%s\" compares the same as "
+           "\"%s\" from \"%s\"",
+           soname, left_basename, left_from, right_basename, right_from );
+    return 0;
+  }
+
+  if( strcmp( soname, left_basename ) == 0 )
+  {
+    /* In some distributions (Debian, Ubuntu, Manjaro)
+     * libgcc_s.so.1 is a plain file, not a symlink to a
+     * version-suffixed version. We cannot know just from the name
+     * whether that's older or newer, so assume equal. The caller is
+     * responsible for figuring out which one to prefer. */
+    DEBUG( DEBUG_TOOL,
+           "Unversioned %s \"%s\" from \"%s\" cannot be compared with "
+           "\"%s\" from \"%s\"",
+           soname, left_basename, left_from,
+           right_basename, right_from );
+    return 0;
+  }
+
+  if( strcmp( soname, right_basename ) == 0 )
+  {
+    /* The same, but the other way round */
+    DEBUG( DEBUG_TOOL,
+           "%s \"%s\" from \"%s\" cannot be compared with "
+           "unversioned \"%s\" from \"%s\"",
+           soname, left_basename, left_from,
+           right_basename, right_from );
+    return 0;
+  }
+
   return ( strverscmp( left_basename, right_basename ) );
 }
 
@@ -489,6 +524,12 @@ capture_one( const char *soname, capture_flags flags,
             {
                 const char *needed_path_in_container = container.needed[0].path;
 
+                /* TODO: Ideally we would actually dlopen the libraries and
+                 * inspect their symbol tables, either in ambiguous cases
+                 * or always - but that's easier said than done, because
+                 * private symbols exist. For now we just use
+                 * library_cmp_by_name(). */
+
                 /* If equal, we prefer the provider over the container */
                 if( library_cmp_by_name( needed_name,
                                          needed_path_in_container,
-- 
GitLab