Hi.Recent commit 555276f8594087ba15e0d58e38cd2186b9f39f6d introduced final cleanup of node->as_eventset in ExecAppendAsyncEventWait(). Unfortunately, now this function can return in the middle of TRY/FINALLY block, without restoring PG_exception_stack.
We found this while working on our FDW. Unfortunately, I couldn't reproduce the issue with postgres_fdw, but it seems it is also affected.
The following patch heals the issue. -- l Best regards, Alexander Pyhalov, Postgres Professional
From 025f40894d6d8f499144f0f7c45c0a124a46c408 Mon Sep 17 00:00:00 2001 From: Alexander Pyhalov <a.pyha...@postgrespro.ru> Date: Fri, 23 Feb 2024 13:06:40 +0300 Subject: [PATCH] Avoid corrupting PG_exception_stack in ExecAppendAsyncEventWait() After commit 555276f8594087ba15e0d58e38cd2186b9f39f6d ExecAppendAsyncEventWait() could corrupt PG_exception_stack after returning in the the middle of PG_TRY()/PG_END_TRY() block. It should exit only after PG_END_TRY(). --- src/backend/executor/nodeAppend.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index baba3ceea23..42962e80177 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -1052,21 +1052,22 @@ ExecAppendAsyncEventWait(AppendState *node) */ if (GetNumRegisteredWaitEvents(node->as_eventset) == 1) { - FreeWaitEventSet(node->as_eventset); - node->as_eventset = NULL; - return; + /* Return after PG_TRY()/PG_END_TRY() block */ + noccurred = 0; } + else + { + /* Return at most EVENT_BUFFER_SIZE events in one call. */ + if (nevents > EVENT_BUFFER_SIZE) + nevents = EVENT_BUFFER_SIZE; - /* Return at most EVENT_BUFFER_SIZE events in one call. */ - if (nevents > EVENT_BUFFER_SIZE) - nevents = EVENT_BUFFER_SIZE; - - /* - * If the timeout is -1, wait until at least one event occurs. If the - * timeout is 0, poll for events, but do not wait at all. - */ - noccurred = WaitEventSetWait(node->as_eventset, timeout, occurred_event, - nevents, WAIT_EVENT_APPEND_READY); + /* + * If the timeout is -1, wait until at least one event occurs. If + * the timeout is 0, poll for events, but do not wait at all. + */ + noccurred = WaitEventSetWait(node->as_eventset, timeout, occurred_event, + nevents, WAIT_EVENT_APPEND_READY); + } } PG_FINALLY(); { -- 2.34.1