Skip to content

Commit 172c53e

Browse files
committed
Prevent interrupts while reporting non-ERROR elog messages.
This should eliminate the risk of recursive entry to syslog(3), which appears to be the cause of the hang reported in bug #9551 from James Morton. Arguably, the real problem here is auth.c's willingness to turn on ImmediateInterruptOK while executing fairly wide swaths of backend code. We may well need to work at narrowing the code ranges in which the authentication_timeout interrupt is enabled. For the moment, though, this is a cheap and reasonably noninvasive fix for a field-reported failure; the other approach would be complex and not necessarily bug-free itself. Back-patch to all supported branches.
1 parent e2bccdf commit 172c53e

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

src/backend/utils/error/elog.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,25 @@ errfinish(int dummy,...)
385385
{
386386
ErrorData *edata = &errordata[errordata_stack_depth];
387387
int elevel = edata->elevel;
388+
bool save_ImmediateInterruptOK;
388389
MemoryContext oldcontext;
389390
ErrorContextCallback *econtext;
390391

391392
recursion_depth++;
392393
CHECK_STACK_DEPTH();
393394

395+
/*
396+
* Ensure we can't get interrupted while performing error reporting. This
397+
* is needed to prevent recursive entry to functions like syslog(), which
398+
* may not be re-entrant.
399+
*
400+
* Note: other places that save-and-clear ImmediateInterruptOK also do
401+
* HOLD_INTERRUPTS(), but that should not be necessary here since we
402+
* don't call anything that could turn on ImmediateInterruptOK.
403+
*/
404+
save_ImmediateInterruptOK = ImmediateInterruptOK;
405+
ImmediateInterruptOK = false;
406+
394407
/*
395408
* Do processing in ErrorContext, which we hope has enough reserved space
396409
* to report an error.
@@ -416,17 +429,16 @@ errfinish(int dummy,...)
416429
/*
417430
* We do some minimal cleanup before longjmp'ing so that handlers can
418431
* execute in a reasonably sane state.
419-
*/
420-
421-
/* This is just in case the error came while waiting for input */
422-
ImmediateInterruptOK = false;
423-
424-
/*
432+
*
425433
* Reset InterruptHoldoffCount in case we ereport'd from inside an
426434
* interrupt holdoff section. (We assume here that no handler will
427435
* itself be inside a holdoff section. If necessary, such a handler
428436
* could save and restore InterruptHoldoffCount for itself, but this
429437
* should make life easier for most.)
438+
*
439+
* Note that we intentionally don't restore ImmediateInterruptOK here,
440+
* even if it was set at entry. We definitely don't want that on
441+
* while doing error cleanup.
430442
*/
431443
InterruptHoldoffCount = 0;
432444

@@ -483,10 +495,7 @@ errfinish(int dummy,...)
483495
{
484496
/*
485497
* For a FATAL error, we let proc_exit clean up and exit.
486-
*/
487-
ImmediateInterruptOK = false;
488-
489-
/*
498+
*
490499
* If we just reported a startup failure, the client will disconnect
491500
* on receiving it, so don't send any more to the client.
492501
*/
@@ -519,15 +528,18 @@ errfinish(int dummy,...)
519528
* XXX: what if we are *in* the postmaster? abort() won't kill our
520529
* children...
521530
*/
522-
ImmediateInterruptOK = false;
523531
fflush(stdout);
524532
fflush(stderr);
525533
abort();
526534
}
527535

528536
/*
529-
* We reach here if elevel <= WARNING. OK to return to caller.
530-
*
537+
* We reach here if elevel <= WARNING. OK to return to caller, so restore
538+
* caller's setting of ImmediateInterruptOK.
539+
*/
540+
ImmediateInterruptOK = save_ImmediateInterruptOK;
541+
542+
/*
531543
* But check for cancel/die interrupt first --- this is so that the user
532544
* can stop a query emitting tons of notice or warning messages, even if
533545
* it's in a loop that otherwise fails to check for interrupts.

0 commit comments

Comments
 (0)