From: Tom Lane Date: Mon, 18 Mar 2019 21:54:24 +0000 (-0400) Subject: Fix memory leak in printtup.c. X-Git-Tag: REL_12_BETA1~499 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f2004f19ed9c9228d3ea2b12379ccb4b9212641f;p=postgresql 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 --- diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index e4ee5c9d34..44add482d3 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;