Home | History | Annotate | Line # | Download | only in recipes
      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 # AIX reports symbol names differently
     28 plan skip_all => "Test is disabled on AIX" if config('target') =~ m|^aix|;
     29 plan skip_all => "This is unsupported on platforms that don't have 'nm'"
     30     unless IPC::Cmd::can_run('nm');
     31 
     32 note
     33     "NOTE: developer test!  It's possible that it won't run on your\n",
     34     "platform, and that's perfectly fine.  This is mainly for developers\n",
     35     "on Unix to check that our shared libraries are consistent with the\n",
     36     "ordinals (util/*.num in the source tree), and that our static libraries\n",
     37     "don't share symbols, something that should be a good enough check for\n",
     38     "the other platforms as well.\n";
     39 
     40 my %stlibname;
     41 my %shlibname;
     42 my %stlibpath;
     43 my %shlibpath;
     44 my %defpath;
     45 foreach (qw(crypto ssl)) {
     46     $stlibname{$_} = platform->staticlib("lib$_");
     47     $stlibpath{$_} = bldtop_file($stlibname{$_});
     48     $shlibname{$_} = platform->sharedlib("lib$_") unless disabled('shared');
     49     $shlibpath{$_} = bldtop_file($shlibname{$_})  unless disabled('shared');
     50 }
     51 
     52 my $testcount
     53     =  1                        # Check for static library symbols duplicates
     54     ;
     55 $testcount
     56     += (scalar keys %shlibpath) # Check for missing symbols in shared lib
     57     unless disabled('shared');
     58 
     59 plan tests => $testcount;
     60 
     61 ######################################################################
     62 # Collect symbols
     63 # [3 tests per library]
     64 
     65 my %stsymbols;                  # Static library symbols
     66 my %shsymbols;                  # Shared library symbols
     67 my %defsymbols;                 # Symbols taken from ordinals
     68 foreach (sort keys %stlibname) {
     69     my $stlib_cmd = "nm -Pg $stlibpath{$_} 2> /dev/null";
     70     my $shlib_cmd = "nm -DPg $shlibpath{$_} 2> /dev/null";
     71     my @stlib_lines;
     72     my @shlib_lines;
     73     *OSTDERR = *STDERR;
     74     *OSTDOUT = *STDOUT;
     75     open STDERR, ">", devnull();
     76     open STDOUT, ">", devnull();
     77     @stlib_lines = map { s|\R$||; $_ } `$stlib_cmd`;
     78     if ($? != 0) {
     79         note "running '$stlib_cmd' => $?";
     80         @stlib_lines = ();
     81     }
     82     unless (disabled('shared')) {
     83         @shlib_lines = map { s|\R$||; $_ } `$shlib_cmd`;
     84         if ($? != 0) {
     85             note "running '$shlib_cmd' => $?";
     86             @shlib_lines = ();
     87         }
     88     }
     89     close STDERR;
     90     close STDOUT;
     91     *STDERR = *OSTDERR;
     92     *STDOUT = *OSTDOUT;
     93 
     94     my $bldtop = bldtop_dir();
     95     my @def_lines;
     96     unless (disabled('shared')) {
     97         indir $bldtop => sub {
     98             my $mkdefpath = srctop_file("util", "mkdef.pl");
     99             my $def_path = srctop_file("util", "lib$_.num");
    100             my $def_cmd = "$^X $mkdefpath --ordinals $def_path --name $_ --OS linux 2> /dev/null";
    101             @def_lines = map { s|\R$||; $_ } `$def_cmd`;
    102             if ($? != 0) {
    103                 note "running 'cd $bldtop; $def_cmd' => $?";
    104                 @def_lines = ();
    105             }
    106         }, create => 0, cleanup => 0;
    107     }
    108 
    109     note "Number of lines in \@stlib_lines before massaging: ", scalar @stlib_lines;
    110     unless (disabled('shared')) {
    111         note "Number of lines in \@shlib_lines before massaging: ", scalar @shlib_lines;
    112         note "Number of lines in \@def_lines before massaging: ", scalar @def_lines;
    113     }
    114 
    115     # Massage the nm output to only contain defined symbols
    116     my @arrays = ( \@stlib_lines );
    117     push @arrays, \@shlib_lines unless disabled('shared');
    118     foreach (@arrays) {
    119         my %commons;
    120         foreach (@$_) {
    121             if (m|^(.*) C .*|) {
    122                 $commons{$1}++;
    123             }
    124         }
    125         foreach (sort keys %commons) {
    126             note "Common symbol: $_";
    127         }
    128 
    129         @$_ =
    130             sort
    131             ( map {
    132                   # Drop the first space and everything following it
    133                   s| .*||;
    134                   # Drop OpenSSL dynamic version information if there is any
    135                   s|\@\@.+$||;
    136                   # Return the result
    137                   $_
    138               }
    139               # Drop any symbol starting with a double underscore, they
    140               # are reserved for the compiler / system ABI and are none
    141               # of our business
    142               grep !m|^__|,
    143               # Only look at external definitions
    144               grep m|.* [BDST] .*|,
    145               @$_ ),
    146             keys %commons;
    147     }
    148 
    149     # Massage the mkdef.pl output to only contain global symbols
    150     # The output we got is in Unix .map format, which has a global
    151     # and a local section.  We're only interested in the global
    152     # section.
    153     my $in_global = 0;
    154     unless (disabled('shared')) {
    155         @def_lines =
    156             sort
    157             map { s|;||; s|\s+||g; $_ }
    158             grep { $in_global = 1 if m|global:|;
    159                    $in_global = 0 if m|local:|;
    160                    $in_global = 0 if m|\}|;
    161                    $in_global && m|;|; } @def_lines;
    162     }
    163 
    164     note "Number of lines in \@stlib_lines after massaging: ", scalar @stlib_lines;
    165     unless (disabled('shared')) {
    166 
    167         note "Number of lines in \@shlib_lines after massaging: ", scalar @shlib_lines;
    168         note "Number of lines in \@def_lines after massaging: ", scalar @def_lines;
    169     }
    170 
    171     $stsymbols{$_} = [ @stlib_lines ];
    172     unless (disabled('shared')) {
    173         $shsymbols{$_} = [ @shlib_lines ];
    174         $defsymbols{$_} = [ @def_lines ];
    175     }
    176 }
    177 
    178 ######################################################################
    179 # Check that there are no duplicate symbols in all our static libraries
    180 # combined
    181 # [1 test]
    182 
    183 my %symbols;
    184 foreach (sort keys %stlibname) {
    185     foreach (@{$stsymbols{$_}}) {
    186         $symbols{$_}++;
    187     }
    188 }
    189 my @duplicates = sort grep { $symbols{$_} > 1 } keys %symbols;
    190 if (@duplicates) {
    191     note "Duplicates:";
    192     note join('\n', @duplicates);
    193 }
    194 ok(scalar @duplicates == 0, "checking no duplicate symbols in static libraries");
    195 
    196 ######################################################################
    197 # Check that the exported symbols in our shared libraries are consistent
    198 # with our ordinals files.
    199 # [1 test per library]
    200 
    201 unless (disabled('shared')) {
    202     foreach (sort keys %stlibname) {
    203         # Maintain lists of symbols that are missing in the shared library,
    204         # or that are extra.
    205         my @missing = ();
    206         my @extra = ();
    207 
    208         my @sh_symbols = ( @{$shsymbols{$_}} );
    209         my @def_symbols = ( @{$defsymbols{$_}} );
    210 
    211         while (scalar @sh_symbols || scalar @def_symbols) {
    212             my $sh_first = $sh_symbols[0];
    213             my $def_first = $def_symbols[0];
    214 
    215             if (!defined($sh_first)) {
    216                 push @missing, shift @def_symbols;
    217             } elsif (!defined($def_first)) {
    218                 push @extra, shift @sh_symbols;
    219             } elsif ($sh_first gt $def_first) {
    220                 push @missing, shift @def_symbols;
    221             } elsif ($sh_first lt $def_first) {
    222                 push @extra, shift @sh_symbols;
    223             } else {
    224                 shift @def_symbols;
    225                 shift @sh_symbols;
    226             }
    227         }
    228 
    229         if (scalar @missing) {
    230             note "The following symbols are missing in $_:";
    231             foreach (@missing) {
    232                 note "  $_";
    233             }
    234         }
    235         if (scalar @extra) {
    236             note "The following symbols are extra in $_:";
    237             foreach (@extra) {
    238                 note "  $_";
    239             }
    240         }
    241         ok(scalar @missing == 0,
    242            "check that there are no missing symbols in $_");
    243     }
    244 }
    245