aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/large_object/inv_api.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2021-11-03 10:28:52 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2021-11-03 10:52:38 +0200
commit6b1b405ebfdce9da47f59d8d4144b1168709fbce (patch)
treede6392efc4c0ae3b8985c0190ad4f80aa419aab0 /src/backend/storage/large_object/inv_api.c
parentef6f047d2c87b91318364341c058dd6b715951b2 (diff)
downloadpostgresql-6b1b405ebfdce9da47f59d8d4144b1168709fbce.tar.gz
postgresql-6b1b405ebfdce9da47f59d8d4144b1168709fbce.zip
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
Diffstat (limited to 'src/backend/storage/large_object/inv_api.c')
-rw-r--r--src/backend/storage/large_object/inv_api.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index bee234bffc9..c98606a7d58 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -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);
}