Bug#860979: dpkg-dev: dpkg-shlibdeps regression due to the /usr-merge changes

2017-04-22 Thread Guillem Jover
Package: dpkg-dev
Version: 1.18.17
Severity: serious
Tags: patch

Hi!

Commit a927295c93fb7a17742441aa863aaffcf4a351b5 introduced a severe
regression related to ignoring the order of the found shared library
pathnames, very carefully curated over time in the find_library()
function. Which I already mentioned as my biggest gut-feeling concern
at the time (for which I should have known better and push back instead
of succumbing to the unpleasant pressure at the timeā€¦).

This was reported on IRC by Helmut Grohne as being detected on one of
the marvelous rebootstrap runs. An easy reproducer is to install on a
clean amd64 system libc6-amd64:i386, and build anything that depends
on libc6. The binary generated might contain a wrong and unsatisifiable
dependency, because it might emit libc6-amd64 (w/o the arch-qualifier,
which does not exist on amd64) instead of just libc6.

I've prepared the most minimal patch I could come up with up to now,
attached, which fixes that specific problem. But I've not given it
much further testing yet. So I'm a bit hesitant to push this into
1.18.24, because it has the potential to break havoc. :( Of course
there's always the other option of reverting the /usr-merge change
altogetherā€¦

Thanks,
Guillem
From aa1ad5755490cb90a309f2d3daf6539d0b4762cb Mon Sep 17 00:00:00 2001
From: Guillem Jover 
Date: Sun, 23 Apr 2017 04:51:58 +0200
Subject: [PATCH] dpkg-shlibdeps: Preserve the order when scanning
 symbols/shlibs files

Regression introduced in commit a927295c93fb7a17742441aa863aaffcf4a351b5.

The code was getting all the possible shared library pathnames for the
wanted SONAME, but was not preserving the order carefully constructed
in find_library(), so we were overwriting symbols/shlibs information
when parsing multiple entries, and selecting the symbols/shlibs files
randomly based on the perl hash order.

This causes regressions when multiple packages provides the same
SONAME on different directories. An example would be libc6:amd64
and libc6-amd64:i386.

Closes: #
Reported-by: Helmut Grohne 
---
 scripts/dpkg-shlibdeps.pl | 74 ---
 1 file changed, 51 insertions(+), 23 deletions(-)

diff --git a/scripts/dpkg-shlibdeps.pl b/scripts/dpkg-shlibdeps.pl
index 0978f33b9..b314202f1 100755
--- a/scripts/dpkg-shlibdeps.pl
+++ b/scripts/dpkg-shlibdeps.pl
@@ -191,6 +191,7 @@ foreach my $file (keys %exec) {
 # Load symbols files for all needed libraries (identified by SONAME)
 my %libfiles;
 my %altlibfiles;
+my %soname_libs;
 my %soname_notfound;
 my %alt_soname;
 foreach my $soname (@sonames) {
@@ -209,6 +210,11 @@ foreach my $file (keys %exec) {
 	}
 	next;
 	}
+
+	# Track shared libraries for a given SONAME.
+	push @{$soname_libs{$soname}}, @libs;
+
+	# Track shared libraries for package mapping.
 	foreach my $lib (@libs) {
 	$libfiles{$lib} = $soname;
 	my $reallib = realpath($lib);
@@ -222,9 +228,11 @@ foreach my $file (keys %exec) {
 my $symfile = Dpkg::Shlibs::SymbolFile->new();
 my $dumplibs_wo_symfile = Dpkg::Shlibs::Objdump->new();
 my @soname_wo_symfile;
-foreach my $lib (keys %libfiles) {
-	my $soname = $libfiles{$lib};
+SONAME: foreach my $soname (@sonames) {
+  # Select the first good entry from the ordered list that we got from
+  # find_library(), and skip to the next SONAME.
 
+  foreach my $lib (@{$soname_libs{$soname}}) {
 	if (none { $_ ne '' } @{$file2pkg->{$lib}}) {
 	# The path of the library as calculated is not the
 	# official path of a packaged file, try to fallback on
@@ -244,6 +252,7 @@ foreach my $file (keys %exec) {
 	}
 
 	# Load symbols/shlibs files from packages providing libraries
+	my $missing_wanted_shlibs_info = 0;
 	foreach my $pkg (@{$file2pkg->{$lib}}) {
 	my $symfile_path;
 my $haslocaldep = 0;
@@ -273,6 +282,9 @@ foreach my $file (keys %exec) {
 		my $minver = $symfile->get_smallest_version($soname) || '';
 		update_dependency_version($dep, $minver);
 		debug(2, " Minimal version of ($dep) initialized with ($minver)");
+
+		# Found a symbols file for the SONAME.
+		next SONAME;
 	} else {
 		# No symbol file found, fall back to standard shlibs
 debug(1, "Using shlibs+objdump for $soname (file $lib)");
@@ -284,31 +296,47 @@ foreach my $file (keys %exec) {
 		$alt_soname{$id} = $soname;
 		}
 		push @soname_wo_symfile, $soname;
+
 		# Only try to generate a dependency for libraries with a SONAME
-		if ($libobj->is_public_library() and not
-		add_shlibs_dep($soname, $pkg, $lib)) {
-		# This failure is fairly new, try to be kind by
-		# ignoring as many cases that can be safely ignored
-		my $ignore = 0;
-		# 1/ when the lib and the binary are in the same
-		# package
-		my $root_file = guess_pkg_root_dir($file);
-		my $root_lib = guess_pkg_root_dir($lib);
-		$ignore++ if defined $root_file and defined $root_lib
-			

Bug#860932: dpkg-shlibdeps should throw an error when generating unsatisfiable dependencies

2017-04-22 Thread Johannes Schauer
Package: dpkg
Version: 1.18.23
Severity: wishlist

Hi,

I recently hacked on a series of packages when I noticed that
dpkg-shlibdeps emitted the following dependency for my new packaging of
src:linphone:

libbellesip0 (>= 1.6.1), libbellesip0 (<< 1.6.0)

The reason for that was probably that the source package libbellesip0
came from had debian/libbellesip0.symbols file which enforced the
"libbellesip0 (<< 1.6.0)" version restriction while at the same time the
symbols indicated that "libbellesip0 (>= 1.6.1)" was needed. From
debian/libbellesip0.symbols:

libbellesip.so.0 libbellesip0 #MINVER#, libbellesip0 (<< 1.6.0)
[...]
belle_sip_body_handler_begin_recv_transfer@Base 1.6.1
belle_sip_body_handler_begin_send_transfer@Base 1.6.1
[...]

I think there are several places here that could emit some sort of error
message. One is when building src:linphone, dpkg-shlibdeps could
probably check whether the final dependency string it puts into the
substitution variable is satisfiable at all and emit a warning or throw
an error if that's not the case.

Maybe another thing that could be done would be to warn if a *.symbols
file is seen with such a dependency restriction as showcased above. But
I don't know if it's possible to do this reliable or if there are cases
where this will lead to false positives.

Thanks!

cheers, josch