diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index d39f3e1b655..cd2155caabd 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -350,6 +350,7 @@ ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase, { ResourceElem *items; uint32 nitems; + bool using_arr; /* * ResourceOwnerSort must've been called already. All the resources are @@ -361,12 +362,14 @@ ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase, { items = owner->arr; nitems = owner->narr; + using_arr = true; } else { Assert(owner->narr == 0); items = owner->hash; nitems = owner->nhash; + using_arr = false; } /* @@ -395,13 +398,20 @@ ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase, elog(WARNING, "resource was not closed: %s", res_str); pfree(res_str); } - kind->ReleaseResource(value); + + /* + * Update stored count to forget the item before calling its + * ReleaseResource method. This avoids double-free crashes in case an + * error gets thrown within ReleaseResource. + */ nitems--; + if (using_arr) + owner->narr = nitems; + else + owner->nhash = nitems; + + kind->ReleaseResource(value); } - if (owner->nhash == 0) - owner->narr = nitems; - else - owner->nhash = nitems; }