From f711555fd2b69e74a33312f5ba8750b8fec97f1f Mon Sep 17 00:00:00 2001 From: BharatDBPG Date: Wed, 19 Nov 2025 12:17:43 +0530 Subject: [PATCH] libpq: Add exit() function check for Meson build and whitelist pthread_exit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Makefile-based build already performs a safety check to ensure that libpq does not accidentally reference exit() or related termination functions. Meson, however, did not run this check. As a result, Meson builds could miss accidental references to exit()-family functions which ideally should never be called inside libpq. This patch adds the missing scan to the Meson build by: • Scanning the libpq .o files using nm and filtering through the same whitelist logic as the Makefile. • Adding pthread_exit() to the Meson whitelist, matching the behavior of the existing Makefile check. With this change, both Makefile and Meson builds apply the same validation for unwanted exit() usage. Signed-off-by: Vasuki[BharatDBPG] --- meson.build | 1 + src/interfaces/libpq/Makefile | 7 ++-- src/interfaces/libpq/meson.build | 70 +++++++++++++++----------------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/meson.build b/meson.build index 24aeffe..e20bfe6 100644 --- a/meson.build +++ b/meson.build @@ -3812,6 +3812,7 @@ alias_target('bin', bin_targets + [libpq_st]) alias_target('pl', pl_targets) alias_target('contrib', contrib_targets) alias_target('testprep', testprep_targets) +alias_target('run-check-libpq', [check_exit_target]) alias_target('world', all_built, docs) alias_target('install-world', install_quiet, installdocs) diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 3bd0e4f..1ad3c60 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -134,9 +134,10 @@ $(stlib): $(OBJS_STATIC) # 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. +# which seems to insert references to that even in pure C code. Excluding +# __tsan_func_exit is necessary when using ThreadSanitizer, which emits this +# symbol as part of its instrumentation of function exits. Excluding +# pthread_exit allows legitimate thread shutdown paths used on some builds. # 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 diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build index 4b1e8a2..4822814 100644 --- a/src/interfaces/libpq/meson.build +++ b/src/interfaces/libpq/meson.build @@ -1,5 +1,4 @@ # Copyright (c) 2022-2025, PostgreSQL Global Development Group - libpq_sources = files( 'fe-auth-oauth.c', 'fe-auth-scram.c', @@ -85,6 +84,38 @@ libpq = declare_dependency( include_directories: [include_directories('.')] ) +# Sanity check to ensure libpq does not contain any unintended references +# to exit() in its object files. Client libraries must not terminate the +# calling process, so we scan all libpq .o files with 'nm' and fail the +# build if a direct exit() reference is found. Certain harmless symbols +# (__cxa_atexit, __tsan_func_exit, pthread_exit) are whitelisted. +# Skip on cross-builds, sanitizer coverage, and Windows + +if not meson.is_cross_build() and not get_option('b_coverage') and host_system != 'windows' + check_exit_target = custom_target( + 'check-libpq-no-exit', + output: 'libpq-nm-stamp', + depends: [libpq_st, libpq_so], + build_by_default: true, + command: [ + 'bash','-eu', '-c', + ''' + echo "Checking that libpq object files do not reference exit()..." + obj_files=$(find src/interfaces/libpq -type f -name "*.o") + for f in $obj_files; do + if nm -u "$f" 2>/dev/null \ + | grep -v -E '__cxa_atexit|__tsan_func_exit|pthread_exit' \ + | grep exit; then + echo "ERROR: exit()-related reference found in: $f" + exit 1 + fi + done + touch @OUTPUT@ + '''.format(meson.current_build_dir()) + ], + ) + +endif private_deps = [ frontend_stlib_code, @@ -147,41 +178,4 @@ tests += { }, } -# Verify that libpq does not reference functions that may invoke exit(). -# -# This check parallels the Makefile logic used in the autoconf build system. -# -# The following symbols are considered safe and therefore ignored: -# - __cxa_atexit : used for C++ static destructors -# - __tsan_func_exit : thread sanitizer instrumentation -# - pthread_exit : used by thread runtimes, harmless here -# -# The test runs only for native builds (not cross-builds) and when code -# coverage is disable - -if not meson.is_cross_build() and not get_option('b_coverage') and host_system != 'sunos' - check_exit_target = custom_target( - 'check-libpq-no-exit', - output: 'libpq-refs-stamp', - depends: libpq_so, - build_by_default: true, - command: [ - 'bash', '-c', - ''' - echo "Running exit() reference check for libpq..." - if nm -A -u @0@ 2>/dev/null | \ - grep -v -e __cxa_atexit -e __tsan_func_exit -e pthread_exit | \ - grep exit; then - echo "ERROR: libpq must not be calling any function which invokes exit()" - exit 1 - else - echo "SUCCESS: No exit() references found in libpq" - fi - '''.format(libpq_so.full_path()) - ], - build_always_stale: true, - capture: false - ) -endif - subdir('po', if_found: libintl) -- 2.43.0