Skip to content

Commit 6c461cb

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 f70a78b commit 6c461cb

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
@@ -410,13 +410,26 @@ errfinish(int dummy,...)
410410
{
411411
ErrorData *edata = &errordata[errordata_stack_depth];
412412
int elevel;
413+
bool save_ImmediateInterruptOK;
413414
MemoryContext oldcontext;
414415
ErrorContextCallback *econtext;
415416

416417
recursion_depth++;
417418
CHECK_STACK_DEPTH();
418419
elevel = edata->elevel;
419420

421+
/*
422+
* Ensure we can't get interrupted while performing error reporting. This
423+
* is needed to prevent recursive entry to functions like syslog(), which
424+
* may not be re-entrant.
425+
*
426+
* Note: other places that save-and-clear ImmediateInterruptOK also do
427+
* HOLD_INTERRUPTS(), but that should not be necessary here since we
428+
* don't call anything that could turn on ImmediateInterruptOK.
429+
*/
430+
save_ImmediateInterruptOK = ImmediateInterruptOK;
431+
ImmediateInterruptOK = false;
432+
420433
/*
421434
* Do processing in ErrorContext, which we hope has enough reserved space
422435
* to report an error.
@@ -442,17 +455,16 @@ errfinish(int dummy,...)
442455
/*
443456
* We do some minimal cleanup before longjmp'ing so that handlers can
444457
* execute in a reasonably sane state.
445-
*/
446-
447-
/* This is just in case the error came while waiting for input */
448-
ImmediateInterruptOK = false;
449-
450-
/*
458+
*
451459
* Reset InterruptHoldoffCount in case we ereport'd from inside an
452460
* interrupt holdoff section. (We assume here that no handler will
453461
* itself be inside a holdoff section. If necessary, such a handler
454462
* could save and restore InterruptHoldoffCount for itself, but this
455463
* should make life easier for most.)
464+
*
465+
* Note that we intentionally don't restore ImmediateInterruptOK here,
466+
* even if it was set at entry. We definitely don't want that on
467+
* while doing error cleanup.
456468
*/
457469
InterruptHoldoffCount = 0;
458470

@@ -519,10 +531,7 @@ errfinish(int dummy,...)
519531
{
520532
/*
521533
* For a FATAL error, we let proc_exit clean up and exit.
522-
*/
523-
ImmediateInterruptOK = false;
524-
525-
/*
534+
*
526535
* If we just reported a startup failure, the client will disconnect
527536
* on receiving it, so don't send any more to the client.
528537
*/
@@ -555,15 +564,18 @@ errfinish(int dummy,...)
555564
* XXX: what if we are *in* the postmaster? abort() won't kill our
556565
* children...
557566
*/
558-
ImmediateInterruptOK = false;
559567
fflush(stdout);
560568
fflush(stderr);
561569
abort();
562570
}
563571

564572
/*
565-
* We reach here if elevel <= WARNING. OK to return to caller.
566-
*
573+
* We reach here if elevel <= WARNING. OK to return to caller, so restore
574+
* caller's setting of ImmediateInterruptOK.
575+
*/
576+
ImmediateInterruptOK = save_ImmediateInterruptOK;
577+
578+
/*
567579
* But check for cancel/die interrupt first --- this is so that the user
568580
* can stop a query emitting tons of notice or warning messages, even if
569581
* it's in a loop that otherwise fails to check for interrupts.

0 commit comments

Comments
 (0)