Add config tests for including provider config files
[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 }