]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/recipes/01-test_symbol_presence.t
Copyright year updates
[thirdparty/openssl.git] / test / recipes / 01-test_symbol_presence.t
1 #! /usr/bin/env perl
2 # -*- mode: Perl -*-
3 # Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
4 #
5 # Licensed under the Apache License 2.0 (the "License"). You may not use
6 # this file except in compliance with the License. You can obtain a copy
7 # in the file LICENSE in the source distribution or at
8 # https://www.openssl.org/source/license.html
9
10 use strict;
11 use File::Spec::Functions qw(devnull);
12 use IPC::Cmd;
13 use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file);
14 use OpenSSL::Test::Utils;
15
16 BEGIN {
17 setup("test_symbol_presence");
18 }
19
20 use lib srctop_dir('Configurations');
21 use lib bldtop_dir('.');
22 use platform;
23
24 plan skip_all => "Test is disabled on NonStop" if config('target') =~ m|^nonstop|;
25 # MacOS arranges symbol names differently
26 plan skip_all => "Test is disabled on MacOS" if config('target') =~ m|^darwin|;
27 plan skip_all => "This is unsupported on platforms that don't have 'nm'"
28 unless IPC::Cmd::can_run('nm');
29
30 note
31 "NOTE: developer test! It's possible that it won't run on your\n",
32 "platform, and that's perfectly fine. This is mainly for developers\n",
33 "on Unix to check that our shared libraries are consistent with the\n",
34 "ordinals (util/*.num in the source tree), and that our static libraries\n",
35 "don't share symbols, something that should be a good enough check for\n",
36 "the other platforms as well.\n";
37
38 my %stlibname;
39 my %shlibname;
40 my %stlibpath;
41 my %shlibpath;
42 my %defpath;
43 foreach (qw(crypto ssl)) {
44 $stlibname{$_} = platform->staticlib("lib$_");
45 $stlibpath{$_} = bldtop_file($stlibname{$_});
46 $shlibname{$_} = platform->sharedlib("lib$_") unless disabled('shared');
47 $shlibpath{$_} = bldtop_file($shlibname{$_}) unless disabled('shared');
48 }
49
50 my $testcount
51 = 1 # Check for static library symbols duplicates
52 ;
53 $testcount
54 += (scalar keys %shlibpath) # Check for missing symbols in shared lib
55 unless disabled('shared');
56
57 plan tests => $testcount;
58
59 ######################################################################
60 # Collect symbols
61 # [3 tests per library]
62
63 my %stsymbols; # Static library symbols
64 my %shsymbols; # Shared library symbols
65 my %defsymbols; # Symbols taken from ordinals
66 foreach (sort keys %stlibname) {
67 my $stlib_cmd = "nm -Pg $stlibpath{$_} 2> /dev/null";
68 my $shlib_cmd = "nm -DPg $shlibpath{$_} 2> /dev/null";
69 my @stlib_lines;
70 my @shlib_lines;
71 *OSTDERR = *STDERR;
72 *OSTDOUT = *STDOUT;
73 open STDERR, ">", devnull();
74 open STDOUT, ">", devnull();
75 @stlib_lines = map { s|\R$||; $_ } `$stlib_cmd`;
76 if ($? != 0) {
77 note "running '$stlib_cmd' => $?";
78 @stlib_lines = ();
79 }
80 unless (disabled('shared')) {
81 @shlib_lines = map { s|\R$||; $_ } `$shlib_cmd`;
82 if ($? != 0) {
83 note "running '$shlib_cmd' => $?";
84 @shlib_lines = ();
85 }
86 }
87 close STDERR;
88 close STDOUT;
89 *STDERR = *OSTDERR;
90 *STDOUT = *OSTDOUT;
91
92 my $bldtop = bldtop_dir();
93 my @def_lines;
94 unless (disabled('shared')) {
95 indir $bldtop => sub {
96 my $mkdefpath = srctop_file("util", "mkdef.pl");
97 my $def_path = srctop_file("util", "lib$_.num");
98 my $def_cmd = "$^X $mkdefpath --ordinals $def_path --name $_ --OS linux 2> /dev/null";
99 @def_lines = map { s|\R$||; $_ } `$def_cmd`;
100 if ($? != 0) {
101 note "running 'cd $bldtop; $def_cmd' => $?";
102 @def_lines = ();
103 }
104 }, create => 0, cleanup => 0;
105 }
106
107 note "Number of lines in \@stlib_lines before massaging: ", scalar @stlib_lines;
108 unless (disabled('shared')) {
109 note "Number of lines in \@shlib_lines before massaging: ", scalar @shlib_lines;
110 note "Number of lines in \@def_lines before massaging: ", scalar @def_lines;
111 }
112
113 # Massage the nm output to only contain defined symbols
114 my @arrays = ( \@stlib_lines );
115 push @arrays, \@shlib_lines unless disabled('shared');
116 foreach (@arrays) {
117 @$_ =
118 sort
119 map {
120 # Drop the first space and everything following it
121 s| .*||;
122 # Drop OpenSSL dynamic version information if there is any
123 s|\@\@.+$||;
124 # Return the result
125 $_
126 }
127 grep(m|.* [BCDST] .*|, @$_);
128 }
129
130 # Massage the mkdef.pl output to only contain global symbols
131 # The output we got is in Unix .map format, which has a global
132 # and a local section. We're only interested in the global
133 # section.
134 my $in_global = 0;
135 unless (disabled('shared')) {
136 @def_lines =
137 sort
138 map { s|;||; s|\s+||g; $_ }
139 grep { $in_global = 1 if m|global:|;
140 $in_global = 0 if m|local:|;
141 $in_global = 0 if m|\}|;
142 $in_global && m|;|; } @def_lines;
143 }
144
145 note "Number of lines in \@stlib_lines after massaging: ", scalar @stlib_lines;
146 unless (disabled('shared')) {
147
148 note "Number of lines in \@shlib_lines after massaging: ", scalar @shlib_lines;
149 note "Number of lines in \@def_lines after massaging: ", scalar @def_lines;
150 }
151
152 $stsymbols{$_} = [ @stlib_lines ];
153 unless (disabled('shared')) {
154 $shsymbols{$_} = [ @shlib_lines ];
155 $defsymbols{$_} = [ @def_lines ];
156 }
157 }
158
159 ######################################################################
160 # Check that there are no duplicate symbols in all our static libraries
161 # combined
162 # [1 test]
163
164 my %symbols;
165 foreach (sort keys %stlibname) {
166 foreach (@{$stsymbols{$_}}) {
167 $symbols{$_}++;
168 }
169 }
170 my @duplicates = sort grep { $symbols{$_} > 1 } keys %symbols;
171 if (@duplicates) {
172 note "Duplicates:";
173 note join('\n', @duplicates);
174 }
175 ok(scalar @duplicates == 0, "checking no duplicate symbols in static libraries");
176
177 ######################################################################
178 # Check that the exported symbols in our shared libraries are consistent
179 # with our ordinals files.
180 # [1 test per library]
181
182 unless (disabled('shared')) {
183 foreach (sort keys %stlibname) {
184 # Maintain lists of symbols that are missing in the shared library,
185 # or that are extra.
186 my @missing = ();
187 my @extra = ();
188
189 my @sh_symbols = ( @{$shsymbols{$_}} );
190 my @def_symbols = ( @{$defsymbols{$_}} );
191
192 while (scalar @sh_symbols || scalar @def_symbols) {
193 my $sh_first = $sh_symbols[0];
194 my $def_first = $def_symbols[0];
195
196 if (!defined($sh_first)) {
197 push @missing, shift @def_symbols;
198 } elsif (!defined($def_first)) {
199 push @extra, shift @sh_symbols;
200 } elsif ($sh_first gt $def_first) {
201 push @missing, shift @def_symbols;
202 } elsif ($sh_first lt $def_first) {
203 push @extra, shift @sh_symbols;
204 } else {
205 shift @def_symbols;
206 shift @sh_symbols;
207 }
208 }
209
210 if (scalar @missing) {
211 note "The following symbols are missing in $_:";
212 foreach (@missing) {
213 note " $_";
214 }
215 }
216 if (scalar @extra) {
217 note "The following symbols are extra in $_:";
218 foreach (@extra) {
219 note " $_";
220 }
221 }
222 ok(scalar @missing == 0,
223 "check that there are no missing symbols in $_");
224 }
225 }