Skip to content

Commit fef01d4

Browse files
committed
Fix snapshot leak if lo_open called on non-existent object.
lo_open registers the currently active snapshot, and checks if the large object exists after that. Normally, snapshots registered by lo_open are unregistered at end of transaction when the lo descriptor is closed, but if we error out before the lo descriptor is added to the list of open descriptors, it is leaked. Fix by moving the snapshot registration to after checking if the large object exists. Reported by Pavel Stehule. Backpatch to 8.4. The snapshot registration system was introduced in 8.4, so prior versions are not affected (and not supported, anyway).
1 parent 5fdab1e commit fef01d4

File tree

1 file changed

+26
-18
lines changed

1 file changed

+26
-18
lines changed

src/backend/storage/large_object/inv_api.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -232,39 +232,47 @@ LargeObjectDesc *
232232
inv_open(Oid lobjId, int flags, MemoryContext mcxt)
233233
{
234234
LargeObjectDesc *retval;
235-
236-
retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,
237-
sizeof(LargeObjectDesc));
238-
239-
retval->id = lobjId;
240-
retval->subid = GetCurrentSubTransactionId();
241-
retval->offset = 0;
235+
Snapshot snapshot = NULL;
236+
int descflags = 0;
242237

243238
if (flags & INV_WRITE)
244239
{
245-
retval->snapshot = SnapshotNow;
246-
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
240+
snapshot = SnapshotNow;
241+
descflags = IFS_WRLOCK | IFS_RDLOCK;
247242
}
248243
else if (flags & INV_READ)
249244
{
250-
/*
251-
* We must register the snapshot in TopTransaction's resowner, because
252-
* it must stay alive until the LO is closed rather than until the
253-
* current portal shuts down.
254-
*/
255-
retval->snapshot = RegisterSnapshotOnOwner(GetActiveSnapshot(),
256-
TopTransactionResourceOwner);
257-
retval->flags = IFS_RDLOCK;
245+
snapshot = GetActiveSnapshot();
246+
descflags = IFS_RDLOCK;
258247
}
259248
else
260249
elog(ERROR, "invalid flags: %d", flags);
261250

262251
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
263-
if (!myLargeObjectExists(lobjId, retval->snapshot))
252+
if (!myLargeObjectExists(lobjId, snapshot))
264253
ereport(ERROR,
265254
(errcode(ERRCODE_UNDEFINED_OBJECT),
266255
errmsg("large object %u does not exist", lobjId)));
267256

257+
/*
258+
* We must register the snapshot in TopTransaction's resowner, because
259+
* it must stay alive until the LO is closed rather than until the
260+
* current portal shuts down. Do this after checking that the LO exists,
261+
* to avoid leaking the snapshot if an error is thrown.
262+
*/
263+
if (snapshot != SnapshotNow)
264+
snapshot = RegisterSnapshotOnOwner(snapshot,
265+
TopTransactionResourceOwner);
266+
267+
/* All set, create a descriptor */
268+
retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,
269+
sizeof(LargeObjectDesc));
270+
retval->id = lobjId;
271+
retval->subid = GetCurrentSubTransactionId();
272+
retval->offset = 0;
273+
retval->snapshot = snapshot;
274+
retval->flags = descflags;
275+
268276
return retval;
269277
}
270278

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy