postgres.git / summary / log / commit / refs

commit    adf27de8eabbf43b049d1a1bb72780e53e8ea863
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Mon Mar 18 21:54:24 2019 +0000
First released in: 12.0, 11.3

    Fix memory leak in printtup.c.
    
    Commit f2dec34e1 changed things so that printtup's output stringinfo
    buffer was allocated outside the per-row temporary context, not inside
    it.  This creates a need to free that buffer explicitly when the temp
    context is freed, but that was overlooked.  In most cases, this is all
    happening inside a portal or executor context that will go away shortly
    anyhow, but that's not always true.  Notably, the stringinfo ends up
    getting leaked when JDBC uses row-at-a-time fetches.  For a query
    that returns wide rows, that adds up after awhile.
    
    Per bug #15700 from Matthias Otterbach.  Back-patch to v11 where the
    faulty code was added.
    
    Discussion: https://postgr.es/m/15700-8c408321a87d56bb@postgresql.org


src/backend/access/common/printtup.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index a1d44157044..f42d1c7e78f 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -61,12 +61,12 @@ typedef struct typedef struct { DestReceiver pub; /* publicly-known function pointers */ - StringInfoData buf; /* output buffer */ Portal portal; /* the Portal we are printing from */ bool sendDescrip; /* send RowDescription at startup? */ TupleDesc attrinfo; /* The attr info we are set up for */ int nattrs; PrinttupAttrInfo *myinfo; /* Cached info about each attr */ + StringInfoData buf; /* output buffer (*not* in tmpcontext) */ MemoryContext tmpcontext; /* Memory context for per-row workspace */ } DR_printtup; @@ -94,6 +94,7 @@ printtup_create_DR(CommandDest dest) self->attrinfo = NULL; self->nattrs = 0; self->myinfo = NULL; + self->buf.data = NULL; self->tmpcontext = NULL; return (DestReceiver *) self; @@ -132,7 +133,10 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo) DR_printtup *myState = (DR_printtup *) self; Portal portal = myState->portal; - /* create buffer to be used for all messages */ + /* + * Create I/O buffer to be used for all messages. This cannot be inside + * tmpcontext, since we want to re-use it across rows. + */ initStringInfo(&myState->buf); /* @@ -544,6 +548,10 @@ printtup_shutdown(DestReceiver *self) myState->attrinfo = NULL; + if (myState->buf.data) + pfree(myState->buf.data); + myState->buf.data = NULL; + if (myState->tmpcontext) MemoryContextDelete(myState->tmpcontext); myState->tmpcontext = NULL; [parent: fc8b39a46eb7]