On 2019-11-04 16:01, Tom Lane wrote:
Now that I've actually looked at the patched code, there's a far more severe problem with it. Namely, that use of PG_FINALLY means that the "finally" segment is run without having popped the error context stack, which means that any error thrown within that segment will sigsetjmp right back to the top, resulting in an infinite loop. (Well, not infinite, because it'll crash out once the error nesting depth limit is hit.) We *must* pop the stack before running recovery code.
I can confirm that that indeed happens. :( Here is a patch to fix it. -- Peter Eisentraut http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From aa758de0919e2356bf46390b89d8b17d20b8c09e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut <pe...@eisentraut.org> Date: Tue, 5 Nov 2019 22:01:18 +0100 Subject: [PATCH] Fix nested error handling in PG_FINALLY We need to pop the error stack before running the user-supplied PG_FINALLY code. Otherwise an error in the cleanup code would end up at the same sigsetjmp() invocation and result in an infinite error handling loop. --- src/backend/utils/adt/xml.c | 2 +- src/include/utils/elog.h | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 3a493dd6bf..2256c24137 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -3864,7 +3864,7 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt) result = xmlBuffer_to_xmltype(buf); } - PG_FINALLY() + PG_FINALLY(); { if (nodefree) nodefree(cur_copy); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 853c2e0709..93f26876b0 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -338,14 +338,19 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack; } \ else \ _do_rethrow = true; \ - { + { \ + PG_exception_stack = _save_exception_stack; \ + error_context_stack = _save_context_stack #define PG_END_TRY() \ } \ - PG_exception_stack = _save_exception_stack; \ - error_context_stack = _save_context_stack; \ if (_do_rethrow) \ PG_RE_THROW(); \ + else \ + { \ + PG_exception_stack = _save_exception_stack; \ + error_context_stack = _save_context_stack; \ + } \ } while (0) /* -- 2.23.0