aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2018-05-19 23:40:19 -0700
committerZac Medico <zmedico@gentoo.org>2018-05-24 13:31:02 -0700
commit1364cd44e7a6232bf425c4573b5bd3d6738d49a4 (patch)
treeb57d4344ae151989b4b828e8f8ed35be1e9d1132
parentdoebuild: eliminate redundant aux_get calls (bug 656394) (diff)
downloadportage-1364cd44e7a6232bf425c4573b5bd3d6738d49a4.tar.gz
portage-1364cd44e7a6232bf425c4573b5bd3d6738d49a4.tar.bz2
portage-1364cd44e7a6232bf425c4573b5bd3d6738d49a4.zip
SonameDepsProcessor: handle internal libs without DT_SONAME (bug 646190)
Packages like ebtables have internal libraries that lack a DT_SONAME field in their ELF header. Consumers of these internal libraries have DT_RUNPATH entries that refer to the directory containing the internal libraries. For library dependencies that are satisfied by internal libraries like this, it is inappropriate for SonameDepsProcessor to include these depenedencies in the REQUIRES metadata, therefore fix SonameDepsProcessor to automatically detect this case and exclude these dependencies from the REQUIRES metadata. This solves incorrect reporting of broken soname dependencies like the following: $ emerge -p --depclean --ignore-soname-deps=n Calculating dependencies... done! * Broken soname dependencies found: * * x86_64: libebt_redirect.so required by: * net-firewall/ebtables-2.0.10.4 * * x86_64: libebt_log.so required by: * net-firewall/ebtables-2.0.10.4 Bug: https://bugs.gentoo.org/646190
-rw-r--r--pym/portage/tests/util/dyn_libs/__init__.py0
-rw-r--r--pym/portage/tests/util/dyn_libs/__test__.py0
-rw-r--r--pym/portage/tests/util/dyn_libs/test_soname_deps.py34
-rw-r--r--pym/portage/util/_dyn_libs/soname_deps.py35
4 files changed, 66 insertions, 3 deletions
diff --git a/pym/portage/tests/util/dyn_libs/__init__.py b/pym/portage/tests/util/dyn_libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pym/portage/tests/util/dyn_libs/__init__.py
diff --git a/pym/portage/tests/util/dyn_libs/__test__.py b/pym/portage/tests/util/dyn_libs/__test__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pym/portage/tests/util/dyn_libs/__test__.py
diff --git a/pym/portage/tests/util/dyn_libs/test_soname_deps.py b/pym/portage/tests/util/dyn_libs/test_soname_deps.py
new file mode 100644
index 000000000..823890c91
--- /dev/null
+++ b/pym/portage/tests/util/dyn_libs/test_soname_deps.py
@@ -0,0 +1,34 @@
+# Copyright 2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util._dyn_libs.NeededEntry import NeededEntry
+from portage.util._dyn_libs.soname_deps import SonameDepsProcessor
+
+
+class SonameDepsProcessorTestCase(TestCase):
+
+ def testInternalLibsWithoutSoname(self):
+ """
+ Test handling of internal libraries that lack an soname, which are
+ resolved via DT_RUNPATH, see ebtables for example (bug 646190).
+ """
+ needed_elf_2 = """
+X86_64;/sbin/ebtables;;/lib64/ebtables;libebt_802_3.so,libebtable_broute.so,libc.so.6;x86_64
+X86_64;/lib64/ebtables/libebtable_broute.so;;;libc.so.6;x86_64
+X86_64;/lib64/ebtables/libebt_802_3.so;;;libc.so.6;x86_64
+"""
+ soname_deps = SonameDepsProcessor('', '')
+
+ for line in needed_elf_2.splitlines():
+ if not line:
+ continue
+ entry = NeededEntry.parse(None, line)
+ soname_deps.add(entry)
+
+ self.assertEqual(soname_deps.provides, None)
+ # Prior to the fix for bug 646190, REQUIRES contained references to
+ # the internal libebt* libraries which are resolved via a DT_RUNPATH
+ # entry referring to the /lib64/ebtables directory that contains the
+ # internal libraries.
+ self.assertEqual(soname_deps.requires, 'x86_64: libc.so.6\n')
diff --git a/pym/portage/util/_dyn_libs/soname_deps.py b/pym/portage/util/_dyn_libs/soname_deps.py
index a7d595429..c6302afc2 100644
--- a/pym/portage/util/_dyn_libs/soname_deps.py
+++ b/pym/portage/util/_dyn_libs/soname_deps.py
@@ -9,6 +9,11 @@ import os
import re
from portage.util import shlex_split
+from portage.util import (
+ normalize_path,
+ varexpand,
+)
+
class SonameDepsProcessor(object):
"""
@@ -31,6 +36,7 @@ class SonameDepsProcessor(object):
self._requires_map = {}
self._provides_map = {}
self._provides_unfiltered = {}
+ self._basename_map = {}
self._provides = None
self._requires = None
self._intersected = False
@@ -62,15 +68,24 @@ class SonameDepsProcessor(object):
raise AssertionError(
"Missing multilib category data: %s" % entry.filename)
+ self._basename_map.setdefault(
+ os.path.basename(entry.filename), []).append(entry)
+
if entry.needed and (
self._requires_exclude is None or
self._requires_exclude.match(
entry.filename.lstrip(os.sep)) is None):
+ runpaths = frozenset()
+ if entry.runpaths is not None:
+ expand = {"ORIGIN": os.path.dirname(entry.filename)}
+ runpaths = frozenset(normalize_path(varexpand(x, expand,
+ error_leader=lambda: "%s: DT_RUNPATH: " % entry.filename))
+ for x in entry.runpaths)
for x in entry.needed:
if (self._requires_exclude is None or
self._requires_exclude.match(x) is None):
self._requires_map.setdefault(
- multilib_cat, set()).add(x)
+ multilib_cat, {}).setdefault(x, set()).add(runpaths)
if entry.soname:
self._provides_unfiltered.setdefault(
@@ -93,9 +108,23 @@ class SonameDepsProcessor(object):
requires_map.setdefault(multilib_cat, set())
provides_map.setdefault(multilib_cat, set())
provides_unfiltered.setdefault(multilib_cat, set())
- for soname in list(requires_map[multilib_cat]):
+ for soname, consumers in list(requires_map[multilib_cat].items()):
if soname in provides_unfiltered[multilib_cat]:
- requires_map[multilib_cat].remove(soname)
+ del requires_map[multilib_cat][soname]
+ elif soname in self._basename_map:
+ # Handle internal libraries that lack an soname, which
+ # are resolved via DT_RUNPATH, see ebtables for example
+ # (bug 646190).
+ for entry in self._basename_map[soname]:
+ if entry.multilib_category != multilib_cat:
+ continue
+ dirname = os.path.dirname(entry.filename)
+ for runpaths in list(consumers):
+ if dirname in runpaths:
+ consumers.remove(runpaths)
+ if not consumers:
+ del requires_map[multilib_cat][soname]
+ break
provides_data = []
for multilib_cat in sorted(provides_map):