summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.global.in1
-rw-r--r--src/interfaces/libpq/Makefile23
-rwxr-xr-xsrc/interfaces/libpq/libpq_check.pl91
-rw-r--r--src/interfaces/libpq/meson.build18
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,