From 4c332d98b1379df451097132e3f51cc5efb92720 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 2 Oct 2026 09:06:30 +0000 Subject: [PATCH v5 3/3] Test PANIC core-dump suppression Use one SQL helper to raise an ERROR in a critical section and intercept SIGABRT with a distinctive exit code, avoiding actual core files. Check disk-full suppression, the default behavior for another errno, explicit errabort(true) reversal with the override off, and the developer override. Use worker I/O for the crash-recovery cycles. Reviewed-by: Nazir Bilal Yavuz --- .../injection_points--1.0.sql | 7 +++ .../injection_points/injection_points.c | 51 +++++++++++++++++ src/test/modules/test_misc/meson.build | 1 + .../modules/test_misc/t/016_panic_no_core.pl | 55 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 src/test/modules/test_misc/t/016_panic_no_core.pl diff --git a/src/test/modules/injection_points/injection_points--1.0.sql b/src/test/modules/injection_points/injection_points--1.0.sql index 2efb307f5bf..28d870819d0 100644 --- a/src/test/modules/injection_points/injection_points--1.0.sql +++ b/src/test/modules/injection_points/injection_points--1.0.sql @@ -48,6 +48,13 @@ RETURNS void AS 'MODULE_PATHNAME', 'injection_points_run' LANGUAGE C PARALLEL UNSAFE; +-- Test PANIC core-dump suppression with ENOSPC or EIO. +CREATE FUNCTION injection_points_test_panic_core_dump(IN disk_full boolean, + IN reenable_abort boolean DEFAULT false) +RETURNS void +AS 'MODULE_PATHNAME', 'injection_points_test_panic_core_dump' +LANGUAGE C STRICT PARALLEL UNSAFE; + -- -- injection_points_cached() -- diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c index 5e1bbc2f5c9..856f0936361 100644 --- a/src/test/modules/injection_points/injection_points.c +++ b/src/test/modules/injection_points/injection_points.c @@ -17,6 +17,11 @@ #include "postgres.h" +#include +#ifndef WIN32 +#include +#endif + #include "fmgr.h" #include "funcapi.h" #include "injection_points.h" @@ -87,12 +92,31 @@ static bool injection_point_local = false; static void injection_shmem_request(void *arg); static void injection_shmem_init(void *arg); +#ifdef WIN32 +static void injection_abort_handler(int signal); +#else +static void injection_abort_handler(SIGNAL_ARGS); +#endif static const ShmemCallbacks injection_shmem_callbacks = { .request_fn = injection_shmem_request, .init_fn = injection_shmem_init, }; +/* + * Intercept abort() without creating a core file. Exit code 42 distinguishes + * this path from the exit code 2 used when a core dump is suppressed. + */ +static void +#ifdef WIN32 +injection_abort_handler(int signal) +#else +injection_abort_handler(SIGNAL_ARGS) +#endif +{ + _exit(42); +} + /* * Routine for shared memory area initialization, used as a callback * when initializing dynamically with a DSM or when loading the module. @@ -455,6 +479,33 @@ injection_points_run(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +/* Test PANIC core-dump suppression with ENOSPC or EIO. */ +PG_FUNCTION_INFO_V1(injection_points_test_panic_core_dump); +Datum +injection_points_test_panic_core_dump(PG_FUNCTION_ARGS) +{ + int errnum = PG_GETARG_BOOL(0) ? ENOSPC : EIO; + bool reenable_abort = PG_GETARG_BOOL(1); + +#ifdef WIN32 + if (signal(SIGABRT, injection_abort_handler) == SIG_ERR) + elog(ERROR, "could not install SIGABRT handler"); +#else + pqsignal(SIGABRT, injection_abort_handler); +#endif + + START_CRIT_SECTION(); + errno = errnum; + ereport(ERROR, + (errcode_for_file_access(), + errnocoredump_on_errno(ENOSPC), + reenable_abort ? errabort(true) : 0, + errmsg("PANIC requested by test"))); + END_CRIT_SECTION(); + + PG_RETURN_VOID(); +} + /* * SQL function for triggering an injection point from cache. */ diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build index 5d81f5b13be..4c520a339f8 100644 --- a/src/test/modules/test_misc/meson.build +++ b/src/test/modules/test_misc/meson.build @@ -24,6 +24,7 @@ tests += { 't/013_temp_obj_multisession.pl', 't/014_log_statement_max_length.pl', 't/015_temp_schema_exit_deferrable.pl', + 't/016_panic_no_core.pl', ], # The injection points are cluster-wide, so disable installcheck 'runningcheck': false, diff --git a/src/test/modules/test_misc/t/016_panic_no_core.pl b/src/test/modules/test_misc/t/016_panic_no_core.pl new file mode 100644 index 00000000000..3f56fc91f84 --- /dev/null +++ b/src/test/modules/test_misc/t/016_panic_no_core.pl @@ -0,0 +1,55 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +plan skip_all => 'Injection points not supported by this build' + unless $ENV{enable_injection_points} eq 'yes'; + +my $node = PostgreSQL::Test::Cluster->new('panic_no_core'); +$node->init; +# Avoid exhausting io_uring resources across repeated crash recovery. +$node->append_conf( + 'postgresql.conf', qq{ +restart_after_crash = on +log_min_messages = warning +force_core_dump_on_panic = off +io_method = worker +}); +$node->start; + +$node->safe_psql('postgres', 'CREATE EXTENSION injection_points'); + +sub check_panic +{ + my ($arguments, $exit_code, $description) = @_; + + my $log_offset = -s $node->logfile; + $node->psql( + 'postgres', "SELECT injection_points_test_panic_core_dump($arguments)"); + + $node->wait_for_log(qr/PANIC:.*PANIC requested by test/, $log_offset); + $node->wait_for_log(qr/\(PID \d+\) exited with exit code $exit_code/, + $log_offset); + ok($node->poll_query_until('postgres', undef, ''), $description); +} + +check_panic('true', 2, 'disk-full PANIC exits without abort'); +check_panic('false', 42, 'other PANIC errors still abort'); +check_panic('true, true', 42, 'errabort(true) restores abort for disk-full PANIC'); + +$node->safe_psql('postgres', + 'ALTER SYSTEM SET force_core_dump_on_panic = on'); +$node->safe_psql('postgres', 'SELECT pg_reload_conf()'); +ok( $node->poll_query_until( + 'postgres', + q{SELECT current_setting('force_core_dump_on_panic') = 'on'}), + 'core dump override is active'); + +check_panic('true', 42, 'override forces abort for disk-full PANIC'); + +$node->stop; +done_testing(); -- 2.43.0