Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2a44383

Browse files
committed
Clean up memory leaks in LO operations by freeing LO's private
memory context at transaction commit or abort.
1 parent 81ced1e commit 2a44383

File tree

3 files changed

+83
-28
lines changed

3 files changed

+83
-28
lines changed

src/backend/access/transam/xact.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.36 1999/05/25 16:07:50 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.37 1999/05/31 22:53:59 tgl Exp $
1111
*
1212
* NOTES
1313
* Transaction aborts can now occur two ways:
@@ -156,8 +156,6 @@
156156
#include <miscadmin.h>
157157
#include <commands/async.h>
158158
#include <commands/sequence.h>
159-
160-
/* included for _lo_commit [PA, 7/17/98] */
161159
#include <libpq/be-fsstubs.h>
162160

163161
static void AbortTransaction(void);
@@ -938,7 +936,7 @@ CommitTransaction()
938936
*/
939937

940938
/* handle commit for large objects [ PA, 7/17/98 ] */
941-
_lo_commit();
939+
lo_commit(true);
942940

943941
/* NOTIFY commit must also come before lower-level cleanup */
944942
AtCommit_Notify();
@@ -1012,6 +1010,7 @@ AbortTransaction()
10121010
* do abort processing
10131011
* ----------------
10141012
*/
1013+
lo_commit(false); /* 'false' means it's abort */
10151014
UnlockBuffers();
10161015
AtAbort_Notify();
10171016
CloseSequences();

src/backend/libpq/be-fsstubs.c

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.33 1999/05/25 16:08:57 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.34 1999/05/31 22:53:57 tgl Exp $
1111
*
1212
* NOTES
1313
* This should be moved to a more appropriate place. It is here
1414
* for lack of a better place.
1515
*
1616
* Builtin functions for open/close/read/write operations on large objects.
1717
*
18-
* These functions operate in the current portal variable context, which
19-
* means the large object descriptors hang around between transactions and
20-
* are not deallocated until explicitly closed, or until the portal is
21-
* closed.
18+
* These functions operate in a private GlobalMemoryContext, which means
19+
* that large object descriptors hang around until we destroy the context.
20+
* That happens in lo_commit(). It'd be possible to prolong the lifetime
21+
* of the context so that LO FDs are good across transactions (for example,
22+
* we could release the context only if we see that no FDs remain open).
23+
* But we'd need additional state in order to do the right thing at the
24+
* end of an aborted transaction. FDs opened during an aborted xact would
25+
* still need to be closed, since they might not be pointing at valid
26+
* relations at all. For now, we'll stick with the existing documented
27+
* semantics of LO FDs: they're only good within a transaction.
28+
*
2229
*-------------------------------------------------------------------------
2330
*/
2431

@@ -37,6 +44,7 @@
3744
#include <utils/memutils.h>
3845
#include <lib/fstack.h>
3946
#include <utils/mcxt.h>
47+
#include <catalog/pg_shadow.h> /* for superuser() */
4048
#include <storage/fd.h> /* for O_ */
4149
#include <storage/large_object.h>
4250
#include <libpq/be-fsstubs.h>
@@ -91,6 +99,11 @@ lo_open(Oid lobjId, int mode)
9199
/* switch context back to orig. */
92100
MemoryContextSwitchTo(currentContext);
93101

102+
#if FSDB
103+
if (fd < 0) /* newLOfd couldn't find a slot */
104+
elog(NOTICE, "Out of space for large object FDs");
105+
#endif
106+
94107
return fd;
95108
}
96109

@@ -144,6 +157,8 @@ lo_read(int fd, char *buf, int len)
144157
elog(ERROR, "lo_read: invalid large obj descriptor (%d)", fd);
145158
return -3;
146159
}
160+
161+
Assert(fscxt != NULL);
147162
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
148163

149164
status = inv_read(cookies[fd], buf, len);
@@ -168,6 +183,8 @@ lo_write(int fd, char *buf, int len)
168183
elog(ERROR, "lo_write: invalid large obj descriptor (%d)", fd);
169184
return -3;
170185
}
186+
187+
Assert(fscxt != NULL);
171188
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
172189

173190
status = inv_write(cookies[fd], buf, len);
@@ -181,7 +198,7 @@ int
181198
lo_lseek(int fd, int offset, int whence)
182199
{
183200
MemoryContext currentContext;
184-
int ret;
201+
int status;
185202

186203
if (fd < 0 || fd >= MAX_LOBJ_FDS)
187204
{
@@ -194,13 +211,14 @@ lo_lseek(int fd, int offset, int whence)
194211
return -3;
195212
}
196213

214+
Assert(fscxt != NULL);
197215
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
198216

199-
ret = inv_seek(cookies[fd], offset, whence);
217+
status = inv_seek(cookies[fd], offset, whence);
200218

201219
MemoryContextSwitchTo(currentContext);
202220

203-
return ret;
221+
return status;
204222
}
205223

206224
Oid
@@ -246,12 +264,26 @@ lo_tell(int fd)
246264
elog(ERROR, "lo_tell: invalid large object descriptor (%d)", fd);
247265
return -3;
248266
}
267+
268+
/*
269+
* We assume we do not need to switch contexts for inv_tell.
270+
* That is true for now, but is probably more than this module
271+
* ought to assume...
272+
*/
249273
return inv_tell(cookies[fd]);
250274
}
251275

252276
int
253277
lo_unlink(Oid lobjId)
254278
{
279+
/*
280+
* inv_destroy does not need a context switch, indeed it doesn't
281+
* touch any LO-specific data structures at all. (Again, that's
282+
* probably more than this module ought to be assuming.)
283+
*
284+
* XXX there ought to be some code to clean up any open LOs that
285+
* reference the specified relation... as is, they remain "open".
286+
*/
255287
return inv_destroy(lobjId);
256288
}
257289

@@ -297,24 +329,31 @@ lo_import(text *filename)
297329
File fd;
298330
int nbytes,
299331
tmp;
300-
301332
char buf[BUFSIZE];
302333
char fnamebuf[FNAME_BUFSIZE];
303334
LargeObjectDesc *lobj;
304335
Oid lobjOid;
305336

337+
if (!superuser())
338+
elog(ERROR, "You must have Postgres superuser privilege to use "
339+
"server-side lo_import().\n\tAnyone can use the "
340+
"client-side lo_import() provided by libpq.");
341+
306342
/*
307343
* open the file to be read in
308344
*/
309-
StrNCpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ + 1);
345+
nbytes = VARSIZE(filename) - VARHDRSZ + 1;
346+
if (nbytes > FNAME_BUFSIZE)
347+
nbytes = FNAME_BUFSIZE;
348+
StrNCpy(fnamebuf, VARDATA(filename), nbytes);
310349
#ifndef __CYGWIN32__
311350
fd = PathNameOpenFile(fnamebuf, O_RDONLY, 0666);
312351
#else
313352
fd = PathNameOpenFile(fnamebuf, O_RDONLY | O_BINARY, 0666);
314353
#endif
315354
if (fd < 0)
316355
{ /* error */
317-
elog(ERROR, "be_lo_import: can't open unix file \"%s\"\n",
356+
elog(ERROR, "lo_import: can't open unix file \"%s\": %m",
318357
fnamebuf);
319358
}
320359

@@ -341,10 +380,8 @@ lo_import(text *filename)
341380
{
342381
tmp = inv_write(lobj, buf, nbytes);
343382
if (tmp < nbytes)
344-
{
345383
elog(ERROR, "lo_import: error while reading \"%s\"",
346384
fnamebuf);
347-
}
348385
}
349386

350387
FileClose(fd);
@@ -363,12 +400,16 @@ lo_export(Oid lobjId, text *filename)
363400
File fd;
364401
int nbytes,
365402
tmp;
366-
367403
char buf[BUFSIZE];
368404
char fnamebuf[FNAME_BUFSIZE];
369405
LargeObjectDesc *lobj;
370406
mode_t oumask;
371407

408+
if (!superuser())
409+
elog(ERROR, "You must have Postgres superuser privilege to use "
410+
"server-side lo_export().\n\tAnyone can use the "
411+
"client-side lo_export() provided by libpq.");
412+
372413
/*
373414
* open the inversion "object"
374415
*/
@@ -378,9 +419,16 @@ lo_export(Oid lobjId, text *filename)
378419

379420
/*
380421
* open the file to be written to
422+
*
423+
* Note: we reduce backend's normal 077 umask to the slightly
424+
* friendlier 022. This code used to drop it all the way to 0,
425+
* but creating world-writable export files doesn't seem wise.
381426
*/
382-
StrNCpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ + 1);
383-
oumask = umask((mode_t) 0);
427+
nbytes = VARSIZE(filename) - VARHDRSZ + 1;
428+
if (nbytes > FNAME_BUFSIZE)
429+
nbytes = FNAME_BUFSIZE;
430+
StrNCpy(fnamebuf, VARDATA(filename), nbytes);
431+
oumask = umask((mode_t) 0022);
384432
#ifndef __CYGWIN32__
385433
fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
386434
#else
@@ -389,7 +437,7 @@ lo_export(Oid lobjId, text *filename)
389437
umask(oumask);
390438
if (fd < 0)
391439
{ /* error */
392-
elog(ERROR, "lo_export: can't open unix file \"%s\"",
440+
elog(ERROR, "lo_export: can't open unix file \"%s\": %m",
393441
fnamebuf);
394442
}
395443

@@ -400,10 +448,8 @@ lo_export(Oid lobjId, text *filename)
400448
{
401449
tmp = FileWrite(fd, buf, nbytes);
402450
if (tmp < nbytes)
403-
{
404451
elog(ERROR, "lo_export: error while writing \"%s\"",
405452
fnamebuf);
406-
}
407453
}
408454

409455
inv_close(lobj);
@@ -417,24 +463,34 @@ lo_export(Oid lobjId, text *filename)
417463
* prepares large objects for transaction commit [PA, 7/17/98]
418464
*/
419465
void
420-
_lo_commit(void)
466+
lo_commit(bool isCommit)
421467
{
422468
int i;
423469
MemoryContext currentContext;
424470

425471
if (fscxt == NULL)
426-
return;
472+
return; /* no LO operations in this xact */
427473

428474
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
429475

476+
/* Clean out still-open index scans (not necessary if aborting)
477+
* and clear cookies array so that LO fds are no longer good.
478+
*/
430479
for (i = 0; i < MAX_LOBJ_FDS; i++)
431480
{
432481
if (cookies[i] != NULL)
433-
inv_cleanindex(cookies[i]);
482+
{
483+
if (isCommit)
484+
inv_cleanindex(cookies[i]);
485+
cookies[i] = NULL;
486+
}
434487
}
435488

436489
MemoryContextSwitchTo(currentContext);
437490

491+
/* Release the LO memory context to prevent permanent memory leaks. */
492+
GlobalMemoryDestroy(fscxt);
493+
fscxt = NULL;
438494
}
439495

440496

src/include/libpq/be-fsstubs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: be-fsstubs.h,v 1.8 1999/02/13 23:21:34 momjian Exp $
9+
* $Id: be-fsstubs.h,v 1.9 1999/05/31 22:53:58 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -40,6 +40,6 @@ extern int lowrite(int fd, struct varlena * wbuf);
4040
/*
4141
* Added for buffer leak prevention [ Pascal André <[email protected]> ]
4242
*/
43-
extern void _lo_commit(void);
43+
extern void lo_commit(bool isCommit);
4444

4545
#endif /* BE_FSSTUBS_H */

0 commit comments

Comments
 (0)