1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-31 03:21:24 +03:00

Allow callback functions to deregister themselves during a call.

Fetch the next-item pointer before the call not after, so that
we aren't dereferencing a dangling pointer if the callback
deregistered itself during the call.  The risky coding pattern
appears in CallXactCallbacks, CallSubXactCallbacks, and
ResourceOwnerReleaseInternal.  (There are some other places that
might be at hazard if they offered deregistration functionality,
but they don't.)

I (tgl) considered back-patching this, but desisted because it
wouldn't be very safe for extensions to rely on this working in
pre-v16 branches.

Hao Wu

Discussion: https://postgr.es/m/CAH+9SWXTiERkmhRke+QCcc+jRH8d5fFHTxh8ZK0-Yn4BSpyaAg@mail.gmail.com
This commit is contained in:
Tom Lane 2022-09-28 11:23:14 -04:00
parent d84a7b290f
commit 4d2a844242
2 changed files with 18 additions and 3 deletions

View File

@ -3656,9 +3656,14 @@ static void
CallXactCallbacks(XactEvent event)
{
XactCallbackItem *item;
XactCallbackItem *next;
for (item = Xact_callbacks; item; item = item->next)
for (item = Xact_callbacks; item; item = next)
{
/* allow callbacks to unregister themselves when called */
next = item->next;
item->callback(event, item->arg);
}
}
@ -3713,9 +3718,14 @@ CallSubXactCallbacks(SubXactEvent event,
SubTransactionId parentSubid)
{
SubXactCallbackItem *item;
SubXactCallbackItem *next;
for (item = SubXact_callbacks; item; item = item->next)
for (item = SubXact_callbacks; item; item = next)
{
/* allow callbacks to unregister themselves when called */
next = item->next;
item->callback(event, mySubid, parentSubid, item->arg);
}
}

View File

@ -501,6 +501,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
ResourceOwner child;
ResourceOwner save;
ResourceReleaseCallbackItem *item;
ResourceReleaseCallbackItem *next;
Datum foundres;
/* Recurse to handle descendants */
@ -701,8 +702,12 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
}
/* Let add-on modules get a chance too */
for (item = ResourceRelease_callbacks; item; item = item->next)
for (item = ResourceRelease_callbacks; item; item = next)
{
/* allow callbacks to unregister themselves when called */
next = item->next;
item->callback(phase, isCommit, isTopLevel, item->arg);
}
CurrentResourceOwner = save;
}