From bf42e2cf8d8c516aa20306a1137eba4d1b4a12a6 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 2 Oct 2026 09:06:30 +0000 Subject: [PATCH v4 1/3] Allow selected PANIC errors to skip core dumps PANIC always calls abort(), which is useful for server bugs but can worsen disk pressure for operational failures such as ENOSPC. Add errabort(bool) to control the current report's core-dump preference, leaving the default unchanged. Keep errnocoredump_on_errno() as a saved-errno convenience wrapper that suppresses only on a match. An explicit errabort(true) can restore abort() after suppression. Marked PANICs use _exit(2) without cleanup callbacks, preserving existing postmaster crash handling. A core-worthy outer PANIC still takes precedence over nested suppression. Add a developer override and document the reporting helpers. Discussion: https://postgr.es/m/20231118222911.trznxgya4hvzapva@awork3.anarazel.de --- doc/src/sgml/config.sgml | 23 ++++++++++ doc/src/sgml/sources.sgml | 25 +++++++++++ src/backend/utils/error/elog.c | 54 +++++++++++++++++++++-- src/backend/utils/misc/guc_parameters.dat | 7 +++ src/include/utils/elog.h | 4 ++ 5 files changed, 110 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f36fbb60101..e57cc0fef61 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -13547,6 +13547,29 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1) + + force_core_dump_on_panic (boolean) + + force_core_dump_on_panic configuration parameter + + + + + Some PANIC errors are marked to terminate without + requesting a core dump. When this option is set to + on, those errors call + abort() instead, which normally produces a core + dump file. This can be useful for debugging, but repeated failures + can consume significant disk space. Unlike + , this parameter controls + the process reporting the PANIC, not the other + processes terminated by the postmaster afterwards. This parameter + can only be set in the postgresql.conf file or on + the server command line. + + + + debug_logical_replication_streaming (enum) diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml index 760f9b69d47..3026f10ff8d 100644 --- a/doc/src/sgml/sources.sgml +++ b/doc/src/sgml/sources.sgml @@ -392,6 +392,31 @@ ereport(ERROR, too much. + + + errabort(bool do_abort) controls whether a + PANIC calls abort(), the default. + Passing false selects _exit(2) + instead, avoiding a core dump without running cleanup callbacks or + changing postmaster crash handling. Calling + errabort(true) restores the default for the current + report. This preference also applies to errors promoted to + PANIC, but does not change ordinary + ERROR or FATAL termination. + An outer PANIC that requests a core dump, or + , still overrides suppression. + + + + + errnocoredump_on_errno(int errnum) is a convenience + wrapper that calls errabort(false) when the + errno saved at the start of the error report matches + errnum. A nonmatch leaves the preference unchanged, + so multiple calls can select more than one error number without undoing + an earlier match. + + diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index b9d2c96b97a..4d588823719 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -117,6 +117,7 @@ int Log_destination = LOG_DESTINATION_STDERR; char *Log_destination_string = NULL; bool syslog_sequence_numbers = true; bool syslog_split_messages = true; +bool force_core_dump_on_panic = false; /* Processed form of backtrace_functions GUC */ static char *backtrace_function_list; @@ -487,6 +488,7 @@ errfinish(const char *filename, int lineno, const char *funcname) { ErrorData *edata = &errordata[errordata_stack_depth]; int elevel; + bool no_core_dump; MemoryContext oldcontext; ErrorContextCallback *econtext; @@ -521,6 +523,17 @@ errfinish(const char *filename, int lineno, const char *funcname) econtext = econtext->previous) econtext->callback(econtext->arg); + /* + * Capture this before releasing the current error stack entry below. A + * core-worthy outer PANIC must not be downgraded by a nested error. + */ + no_core_dump = edata->no_core_dump; + for (int i = 0; no_core_dump && i < errordata_stack_depth; i++) + { + if (errordata[i].elevel >= PANIC && !errordata[i].no_core_dump) + no_core_dump = false; + } + /* * If ERROR (not more nor less) we pass it off to the current handler. * Printing it and popping the stack is the responsibility of the handler. @@ -611,13 +624,16 @@ errfinish(const char *filename, int lineno, const char *funcname) if (elevel >= PANIC) { /* - * Serious crash time. Postmaster will observe SIGABRT process exit - * status and kill the other backends too. + * Serious crash time. SIGABRT and exit code 2 both trigger + * postmaster crash handling. Marked errors use _exit(2) to avoid + * core dumps without running cleanup callbacks. * - * XXX: what if we are *in* the postmaster? abort() won't kill our + * XXX: what if we are *in* the postmaster? Neither path kills our * children... */ fflush(NULL); + if (no_core_dump && !force_core_dump_on_panic) + _exit(2); abort(); } @@ -1652,6 +1668,37 @@ errhidecontext(bool hide_ctx) return 0; /* return value does not matter */ } +/* + * errabort --- set whether a PANIC should call abort() + */ +int +errabort(bool do_abort) +{ + ErrorData *edata = &errordata[errordata_stack_depth]; + + CHECK_STACK_DEPTH(); + edata->no_core_dump = !do_abort; + + return 0; +} + +/* + * errnocoredump_on_errno --- skip a core dump for the specified errno + */ +int +errnocoredump_on_errno(int errnum) +{ + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->saved_errno == errnum) + return errabort(false); + + return 0; /* return value does not matter */ +} + /* * errposition --- add cursor position to the current error */ @@ -2130,6 +2177,7 @@ ThrowErrorData(ErrorData *edata) newedata->internalpos = edata->internalpos; if (edata->internalquery) newedata->internalquery = pstrdup(edata->internalquery); + newedata->no_core_dump = edata->no_core_dump; MemoryContextSwitchTo(oldcontext); recursion_depth--; diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat index c57441f7d98..88b88160265 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -1104,6 +1104,13 @@ options => 'file_extend_method_options', }, +{ name => 'force_core_dump_on_panic', type => 'bool', context => 'PGC_SIGHUP', group => 'DEVELOPER_OPTIONS', + short_desc => 'Force core dumps for PANIC errors marked to skip them.', + flags => 'GUC_NOT_IN_SAMPLE', + variable => 'force_core_dump_on_panic', + boot_val => 'false', +}, + { name => 'from_collapse_limit', type => 'int', context => 'PGC_USERSET', group => 'QUERY_TUNING_OTHER', short_desc => 'Sets the FROM-list size beyond which subqueries are not collapsed.', long_desc => 'The planner will merge subqueries into upper queries if the resulting FROM list would have no more than this many items.', diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 6ae376ba001..6446e5d250f 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -219,6 +219,8 @@ extern int errcontext_msg(const char *fmt, ...) pg_attribute_printf(1, 2); extern int errhidestmt(bool hide_stmt); extern int errhidecontext(bool hide_ctx); +extern int errabort(bool do_abort); +extern int errnocoredump_on_errno(int errnum); extern int errbacktrace(void); @@ -422,6 +424,7 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack; pg_re_throw() extern PGDLLIMPORT sigjmp_buf *PG_exception_stack; +extern PGDLLIMPORT bool force_core_dump_on_panic; /* Stuff that error handlers might want to use */ @@ -439,6 +442,7 @@ typedef struct ErrorData bool output_to_client; /* will report to client? */ bool hide_stmt; /* true to prevent STATEMENT: inclusion */ bool hide_ctx; /* true to prevent CONTEXT: inclusion */ + bool no_core_dump; /* true to skip core dump for PANIC */ const char *filename; /* __FILE__ of ereport() call */ int lineno; /* __LINE__ of ereport() call */ const char *funcname; /* __func__ of ereport() call */ -- 2.43.0