diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.global.in | 1 | ||||
| -rw-r--r-- | src/interfaces/libpq/Makefile | 23 | ||||
| -rwxr-xr-x | src/interfaces/libpq/libpq_check.pl | 91 | ||||
| -rw-r--r-- | src/interfaces/libpq/meson.build | 18 |
4 files changed, 116 insertions, 17 deletions
diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 0aa389bc710..371cd7eba2c 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -292,6 +292,7 @@ FLEX = @FLEX@ FLEXFLAGS = @FLEXFLAGS@ $(LFLAGS) DTRACE = @DTRACE@ DTRACEFLAGS = @DTRACEFLAGS@ +NM = @NM@ ZIC = @ZIC@ # Linking diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index da6650066d4..9fe321147fc 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -129,25 +129,14 @@ $(shlib): $(OBJS_SHLIB) $(stlib): override OBJS += $(OBJS_STATIC) $(stlib): $(OBJS_STATIC) -# Check for functions that libpq must not call, currently just exit(). -# (Ideally we'd reject abort() too, but there are various scenarios where -# build toolchains insert abort() calls, e.g. to implement assert().) -# If nm doesn't exist or doesn't work on shlibs, this test will do nothing, -# which is fine. The exclusion of __cxa_atexit is necessary on OpenBSD, -# which seems to insert references to that even in pure C code. Excluding -# __tsan_func_exit is necessary when using ThreadSanitizer data race detector -# which use this function for instrumentation of function exit. -# Skip the test when profiling, as gcc may insert exit() calls for that. -# Also skip the test on platforms where libpq infrastructure may be provided -# by statically-linked libraries, as we can't expect them to honor this -# coding rule. +# Check for functions that libpq must not call. See libpq_check.pl for the +# full set of platform rules. Skip the test when profiling, as gcc may +# insert exit() calls for that. Also skip the test on platforms where libpq +# infrastructure may be provided by statically-linked libraries, as we can't +# expect them to honor this coding rule. libpq-refs-stamp: $(shlib) ifneq ($(enable_coverage), yes) -ifeq (,$(filter solaris,$(PORTNAME))) - @if nm -A -u $< 2>/dev/null | grep -v -e __cxa_atexit -e __tsan_func_exit | grep exit; then \ - echo 'libpq must not be calling any function which invokes exit'; exit 1; \ - fi -endif + $(PERL) $(srcdir)/libpq_check.pl --input_file $< --nm='$(NM)' endif touch $@ diff --git a/src/interfaces/libpq/libpq_check.pl b/src/interfaces/libpq/libpq_check.pl new file mode 100755 index 00000000000..835638cc5a2 --- /dev/null +++ b/src/interfaces/libpq/libpq_check.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl +# +# src/interfaces/libpq/libpq_check.pl +# +# Copyright (c) 2025, PostgreSQL Global Development Group +# +# Check the state of a libpq library. Currently, this script checks that +# exit() is not called, because client libraries must not terminate the +# host application. +# +# This script is called by both Makefile and Meson. + +use strict; +use warnings FATAL => 'all'; + +use Getopt::Long; +use Config; + +my $nm_path; +my $input_file; +my $stamp_file; +my @problematic_lines; + +Getopt::Long::GetOptions( + 'nm:s' => \$nm_path, + 'input_file:s' => \$input_file, + 'stamp_file:s' => \$stamp_file) or die "$0: wrong arguments\n"; + +die "$0: --input_file must be specified\n" unless defined $input_file; +die "$0: --nm must be specified\n" unless defined $nm_path and -x $nm_path; + +sub create_stamp_file +{ + if (!(-f $stamp_file)) + { + open my $fh, '>', $stamp_file + or die "can't open $stamp_file: $!"; + close $fh; + } +} + +# Skip on Windows and Solaris +if ( $Config{osname} =~ /MSWin32|cygwin|msys/i + || $Config{osname} =~ /solaris/i) +{ + exit 0; +} + +# Run nm to scan for symbols. If nm fails at runtime, skip the check. +open my $fh, '-|', "$nm_path -A -u $input_file 2>/dev/null" + or exit 0; + +while (<$fh>) +{ + # Set of symbols allowed. + + # The exclusion of __cxa_atexit is necessary on OpenBSD, which seems + # to insert references to that even in pure C code. + next if /__cxa_atexit/; + + # Excluding __tsan_func_exit is necessary when using ThreadSanitizer data + # race detector which uses this function for instrumentation of function + # exit. + next if /__tsan_func_exit/; + + # Anything containing "exit" is suspicious. + # (Ideally we should reject abort() too, but there are various scenarios + # where build toolchains insert abort() calls, e.g. to implement + # assert().) + if (/exit/) + { + push @problematic_lines, $_; + } +} +close $fh; + +if (@problematic_lines) +{ + print "libpq must not be calling any function which invokes exit\n"; + print "Problematic symbol references:\n"; + print @problematic_lines; + + exit 1; +} +# Create stamp file, if required +if (defined($stamp_file)) +{ + create_stamp_file(); +} + +exit 0; diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build index a74e885b169..b259c998fa2 100644 --- a/src/interfaces/libpq/meson.build +++ b/src/interfaces/libpq/meson.build @@ -85,6 +85,24 @@ libpq = declare_dependency( include_directories: [include_directories('.')] ) +# Check for functions that libpq must not call. See libpq_check.pl for the +# full set of platform rules. Skip the test when profiling, as gcc may +# insert exit() calls for that. +if nm.found() and not get_option('b_coverage') + custom_target( + 'libpq_check', + input: libpq_so, + output: 'libpq-refs-stamp', + command: [ + perl, files('libpq_check.pl'), + '--input_file', '@INPUT@', + '--stamp_file', '@OUTPUT@', + '--nm', nm.full_path(), + ], + build_by_default: true, + ) +endif + private_deps = [ frontend_stlib_code, libpq_deps, |
