Skip to content

Commit 7a289bb

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 bbe9621 commit 7a289bb

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
@@ -406,12 +406,25 @@ errfinish(int dummy,...)
406406
{
407407
ErrorData *edata = &errordata[errordata_stack_depth];
408408
int elevel = edata->elevel;
409+
bool save_ImmediateInterruptOK;
409410
MemoryContext oldcontext;
410411
ErrorContextCallback *econtext;
411412

412413
recursion_depth++;
413414
CHECK_STACK_DEPTH();
414415

416+
/*
417+
* Ensure we can't get interrupted while performing error reporting. This
418+
* is needed to prevent recursive entry to functions like syslog(), which
419+
* may not be re-entrant.
420+
*
421+
* Note: other places that save-and-clear ImmediateInterruptOK also do
422+
* HOLD_INTERRUPTS(), but that should not be necessary here since we
423+
* don't call anything that could turn on ImmediateInterruptOK.
424+
*/
425+
save_ImmediateInterruptOK = ImmediateInterruptOK;
426+
ImmediateInterruptOK = false;
427+
415428
/*
416429
* Do processing in ErrorContext, which we hope has enough reserved space
417430
* to report an error.
@@ -437,17 +450,16 @@ errfinish(int dummy,...)
437450
/*
438451
* We do some minimal cleanup before longjmp'ing so that handlers can
439452
* execute in a reasonably sane state.
440-
*/
441-
442-
/* This is just in case the error came while waiting for input */
443-
ImmediateInterruptOK = false;
444-
445-
/*
453+
*
446454
* Reset InterruptHoldoffCount in case we ereport'd from inside an
447455
* interrupt holdoff section. (We assume here that no handler will
448456
* itself be inside a holdoff section. If necessary, such a handler
449457
* could save and restore InterruptHoldoffCount for itself, but this
450458
* should make life easier for most.)
459+
*
460+
* Note that we intentionally don't restore ImmediateInterruptOK here,
461+
* even if it was set at entry. We definitely don't want that on
462+
* while doing error cleanup.
451463
*/
452464
InterruptHoldoffCount = 0;
453465

@@ -504,10 +516,7 @@ errfinish(int dummy,...)
504516
{
505517
/*
506518
* For a FATAL error, we let proc_exit clean up and exit.
507-
*/
508-
ImmediateInterruptOK = false;
509-
510-
/*
519+
*
511520
* If we just reported a startup failure, the client will disconnect
512521
* on receiving it, so don't send any more to the client.
513522
*/
@@ -540,15 +549,18 @@ errfinish(int dummy,...)
540549
* XXX: what if we are *in* the postmaster? abort() won't kill our
541550
* children...
542551
*/
543-
ImmediateInterruptOK = false;
544552
fflush(stdout);
545553
fflush(stderr);
546554
abort();
547555
}
548556

549557
/*
550-
* We reach here if elevel <= WARNING. OK to return to caller.
551-
*
558+
* We reach here if elevel <= WARNING. OK to return to caller, so restore
559+
* caller's setting of ImmediateInterruptOK.
560+
*/
561+
ImmediateInterruptOK = save_ImmediateInterruptOK;
562+
563+
/*
552564
* But check for cancel/die interrupt first --- this is so that the user
553565
* can stop a query emitting tons of notice or warning messages, even if
554566
* it's in a loop that otherwise fails to check for interrupts.

0 commit comments

Comments
 (0)