aboutsummaryrefslogtreecommitdiff
path: root/test/recipes/01-test_symbol_presence.t
diff options
context:
space:
mode:
Diffstat (limited to 'test/recipes/01-test_symbol_presence.t')
-rw-r--r--test/recipes/01-test_symbol_presence.t157
1 files changed, 157 insertions, 0 deletions
diff --git a/test/recipes/01-test_symbol_presence.t b/test/recipes/01-test_symbol_presence.t
new file mode 100644
index 000000000000..3de3d2ccf19b
--- /dev/null
+++ b/test/recipes/01-test_symbol_presence.t
@@ -0,0 +1,157 @@
+#! /usr/bin/env perl
+# -*- mode: Perl -*-
+# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use File::Spec::Functions qw(devnull);
+use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file);
+use OpenSSL::Test::Utils;
+
+BEGIN {
+ setup("test_symbol_presence");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+use platform;
+
+plan skip_all => "Test is disabled on NonStop" if config('target') =~ m|^nonstop|;
+# MacOS arranges symbol names differently
+plan skip_all => "Test is disabled on MacOS" if config('target') =~ m|^darwin|;
+plan skip_all => "This is unsupported on MSYS, MinGW or MSWin32"
+ if $^O eq 'msys' or $^O eq 'MSWin32' or config('target') =~ m|^mingw|;
+plan skip_all => "Only useful when building shared libraries"
+ if disabled("shared");
+
+my @libnames = ("crypto", "ssl");
+my $testcount = scalar @libnames;
+
+plan tests => $testcount * 2;
+
+note
+ "NOTE: developer test! It's possible that it won't run on your\n",
+ "platform, and that's perfectly fine. This is mainly for developers\n",
+ "on Unix to check that our shared libraries are consistent with the\n",
+ "ordinals (util/*.num in the source tree), something that should be\n",
+ "good enough a check for the other platforms as well.\n";
+
+foreach my $libname (@libnames) {
+ SKIP:
+ {
+ my $shlibname = platform->sharedlib("lib$libname");
+ my $shlibpath = bldtop_file($shlibname);
+ *OSTDERR = *STDERR;
+ *OSTDOUT = *STDOUT;
+ open STDERR, ">", devnull();
+ open STDOUT, ">", devnull();
+ my @nm_lines = map { s|\R$||; $_ } `nm -DPg $shlibpath 2> /dev/null`;
+ close STDERR;
+ close STDOUT;
+ *STDERR = *OSTDERR;
+ *STDOUT = *OSTDOUT;
+ skip "Can't run 'nm -DPg $shlibpath' => $?... ignoring", 2
+ unless $? == 0;
+
+ my $bldtop = bldtop_dir();
+ my @def_lines;
+ indir $bldtop => sub {
+ my $mkdefpath = srctop_file("util", "mkdef.pl");
+ my $libnumpath = srctop_file("util", "lib$libname.num");
+ @def_lines = map { s|\R$||; $_ } `$^X $mkdefpath --ordinals $libnumpath --name $libname --OS linux 2> /dev/null`;
+ ok($? == 0, "running 'cd $bldtop; $^X $mkdefpath --ordinals $libnumpath --name $libname --OS linux' => $?");
+ }, create => 0, cleanup => 0;
+
+ note "Number of lines in \@nm_lines before massaging: ", scalar @nm_lines;
+ note "Number of lines in \@def_lines before massaging: ", scalar @def_lines;
+
+ # Massage the nm output to only contain defined symbols
+ # Common symbols need separate treatment
+ my %commons;
+ foreach (@nm_lines) {
+ if (m|^(.*) C .*|) {
+ $commons{$1}++;
+ }
+ }
+ foreach (sort keys %commons) {
+ note "Common symbol: $_";
+ }
+
+ @nm_lines =
+ sort
+ ( map {
+ # Drop the first space and everything following it
+ s| .*||;
+ # Drop OpenSSL dynamic version information if there is any
+ s|\@\@.+$||;
+ # Return the result
+ $_
+ }
+ # Drop any symbol starting with a double underscore, they
+ # are reserved for the compiler / system ABI and are none
+ # of our business
+ grep !m|^__|,
+ # Only look at external definitions
+ grep m|.* [BDST] .*|,
+ @nm_lines ),
+ keys %commons;
+
+ # Massage the mkdef.pl output to only contain global symbols
+ # The output we got is in Unix .map format, which has a global
+ # and a local section. We're only interested in the global
+ # section.
+ my $in_global = 0;
+ @def_lines =
+ sort
+ map { s|;||; s|\s+||g; $_ }
+ grep { $in_global = 1 if m|global:|;
+ $in_global = 0 if m|local:|;
+ $in_global = 0 if m|\}|;
+ $in_global && m|;|; } @def_lines;
+
+ note "Number of lines in \@nm_lines after massaging: ", scalar @nm_lines;
+ note "Number of lines in \@def_lines after massaging: ", scalar @def_lines;
+
+ # Maintain lists of symbols that are missing in the shared library,
+ # or that are extra.
+ my @missing = ();
+ my @extra = ();
+
+ while (scalar @nm_lines || scalar @def_lines) {
+ my $nm_first = $nm_lines[0];
+ my $def_first = $def_lines[0];
+
+ if (!defined($nm_first)) {
+ push @missing, shift @def_lines;
+ } elsif (!defined($def_first)) {
+ push @extra, shift @nm_lines;
+ } elsif ($nm_first gt $def_first) {
+ push @missing, shift @def_lines;
+ } elsif ($nm_first lt $def_first) {
+ push @extra, shift @nm_lines;
+ } else {
+ shift @def_lines;
+ shift @nm_lines;
+ }
+ }
+
+ if (scalar @missing) {
+ note "The following symbols are missing in ${shlibname}:";
+ foreach (@missing) {
+ note " $_";
+ }
+ }
+ if (scalar @extra) {
+ note "The following symbols are extra in ${shlibname}:";
+ foreach (@extra) {
+ note " $_";
+ }
+ }
+ ok(scalar @missing == 0,
+ "check that there are no missing symbols in ${shlibname}");
+ }
+}