mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Fix snapshot reference leak if lo_export fails.
If lo_export() fails to open the target file or to write to it, it leaks the created LargeObjectDesc and its snapshot in the top-transaction context and resource owner. That's pretty harmless, it's a small leak after all, but it gives the user a "Snapshot reference leak" warning. Fix by using a short-lived memory context and no resource owner for transient LargeObjectDescs that are opened and closed within one function call. The leak is easiest to reproduce with lo_export() on a directory that doesn't exist, but in principle the other lo_* functions could also fail. Backpatch to all supported versions. Reported-by: Andrew B Reviewed-by: Alvaro Herrera Discussion: https://www.postgresql.org/message-id/32bf767a-2d65-71c4-f170-122f416bab7e@iki.fi
This commit is contained in:
@@ -244,10 +244,12 @@ inv_create(Oid lobjId)
|
||||
/*
|
||||
* inv_open -- access an existing large object.
|
||||
*
|
||||
* Returns:
|
||||
* Large object descriptor, appropriately filled in. The descriptor
|
||||
* and subsidiary data are allocated in the specified memory context,
|
||||
* which must be suitably long-lived for the caller's purposes.
|
||||
* Returns a large object descriptor, appropriately filled in.
|
||||
* The descriptor and subsidiary data are allocated in the specified
|
||||
* memory context, which must be suitably long-lived for the caller's
|
||||
* purposes. If the returned descriptor has a snapshot associated
|
||||
* with it, the caller must ensure that it also lives long enough,
|
||||
* e.g. by calling RegisterSnapshotOnOwner
|
||||
*/
|
||||
LargeObjectDesc *
|
||||
inv_open(Oid lobjId, int flags, MemoryContext mcxt)
|
||||
@@ -314,19 +316,16 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
|
||||
retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,
|
||||
sizeof(LargeObjectDesc));
|
||||
retval->id = lobjId;
|
||||
retval->subid = GetCurrentSubTransactionId();
|
||||
retval->offset = 0;
|
||||
retval->flags = descflags;
|
||||
|
||||
/* caller sets if needed, not used by the functions in this file */
|
||||
retval->subid = InvalidSubTransactionId;
|
||||
|
||||
/*
|
||||
* We must register the snapshot in TopTransaction's resowner, because it
|
||||
* must stay alive until the LO is closed rather than until the current
|
||||
* portal shuts down. Do this last to avoid uselessly leaking the
|
||||
* snapshot if an error is thrown above.
|
||||
* The snapshot (if any) is just the currently active snapshot. The
|
||||
* caller will replace it with a longer-lived copy if needed.
|
||||
*/
|
||||
if (snapshot)
|
||||
snapshot = RegisterSnapshotOnOwner(snapshot,
|
||||
TopTransactionResourceOwner);
|
||||
retval->snapshot = snapshot;
|
||||
|
||||
return retval;
|
||||
@@ -340,10 +339,6 @@ void
|
||||
inv_close(LargeObjectDesc *obj_desc)
|
||||
{
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
|
||||
UnregisterSnapshotFromOwner(obj_desc->snapshot,
|
||||
TopTransactionResourceOwner);
|
||||
|
||||
pfree(obj_desc);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user