1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#! /usr/bin/perl
# Written by Zack Weinberg <zackw at panix.com> in 2017 and 2020.
# To the extent possible under law, Zack Weinberg has waived all
# copyright and related or neighboring rights to this work.
#
# See https://creativecommons.org/publicdomain/zero/1.0/ for further
# details.
# This test is only run if we are building a shared library intended
# to be binary backward compatible with GNU libc (libcrypt.so.1).
# It locates any installed version of libcrypt.so.1, and verifies that
# each public symbol exposed by that library is also exposed by our
# libcrypt.so.1 with a matching symbol version.
#
# Due to limitations in Automake, this program takes parameters from
# the environment:
# $lib_la - full pathname of libcrypt.la
# $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C
# $CC, $NM - names of tools to run (defaults to 'cc' and 'nm' respectively)
# $CFLAGS, $LDFLAGS - options to pass to $CC when linking (default: empty)
use v5.14; # implicit use strict, use feature ':5.14'
use warnings FATAL => 'all';
use utf8;
use open qw(:std :utf8);
no if $] >= 5.022, warnings => 'experimental::re_strict';
use if $] >= 5.022, re => 'strict';
use FindBin ();
use lib $FindBin::Bin;
use TestCommon qw(
compare_symbol_lists
ensure_C_locale
find_real_library
get_symbols
popen
sh_split
skip
subprocess_error
which
);
# Some differences between the symbols exported by heritage libcrypt.so.1
# and our libcrypt.so.1 are expected:
#
# * All of the symbols we define with GLIBC_2.xx version tags are
# compatibility symbols (nm prints only one @); naturally,
# glibc-provided libcrypt.so.1 defines some of those symbols as
# linkable symbols (two @).
#
# * Older versions of libcrypt defined five symbols as linkable,
# with the XCRYPT_2.0 version tag, which are now compatibility-only:
# crypt_gensalt_r, xcrypt, xcrypt_gensalt, xcrypt_gensalt_r, and
# xcrypt_r.
#
# This sub is applied to the symbol listing from the system-provided
# libcrypt.so.1; it edits that listing so that the comparison below
# succeeds despite any expected differences.
sub filter_expected_differences {
my $symbols = shift;
my %filtered;
my $formerly_linkable = qr{
^ (?: crypt_gensalt_r
| xcrypt(?: _r)?
| xcrypt_gensalt(?: _r)?
) @@
}x;
for my $s (keys %{$symbols}) {
$s =~ s/\b@@(?=GLIBC_)/@/;
$s =~ s/\b@@(?=XCRYPT_2\.0)/@/ if $s =~ $formerly_linkable;
$filtered{$s} = 1;
}
return \%filtered;
}
sub find_system_libcrypt {
# Ask the compiler whether a libcrypt.so.1 exists in its search
# path. The compiler option -print-file-name should be supported
# on all operating systems where there's an older libcrypt that we
# can be backward compatible with.
state @CC;
if (!@CC) {
@CC = which($ENV{CC} || 'cc');
skip('C compiler not available') unless @CC;
}
state @CFLAGS;
if (!@CFLAGS) {
@CFLAGS = sh_split($ENV{CFLAGS} || q{});
}
state @LDFLAGS;
if (!@LDFLAGS) {
@LDFLAGS = sh_split($ENV{LDFLAGS} || q{});
}
my $fh =
popen('-|', @CC, @CFLAGS, @LDFLAGS, '-print-file-name=libcrypt.so.1');
my $path;
{
local $/ = undef; # slurp
$path = <$fh>;
}
close $fh or subprocess_error($CC[0]);
chomp $path;
# If we get back either the empty string or the same string we put
# in, it means there is no libcrypt.so.1 on this system.
if ($path eq q{} || $path eq 'libcrypt.so.1') {
skip('no system-provided libcrypt.so.1');
}
return $path;
}
sub get_our_symbols {
return get_symbols(find_real_library(shift, 'shared'));
}
sub get_their_symbols {
return filter_expected_differences(get_symbols(find_system_libcrypt()));
}
#
# Main
#
my $lib_la = $ENV{lib_la} || '/nonexistent';
if (!-f $lib_la) {
print {*STDERR} "usage: lib_la=/path/to/library.la $0";
exit 1;
}
ensure_C_locale();
exit compare_symbol_lists(
get_our_symbols($lib_la),
get_their_symbols(),
'symbol versions',
1, # extra symbols are allowed
);
|