From: Alvaro Herrera Date: Mon, 20 Jul 2015 12:18:08 +0000 (+0200) Subject: Fix (some of) pltcl memory usage X-Git-Tag: REL9_5_ALPHA2~88 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b0b6f8d71f03463854576b30c1b01e5d772076d8;p=postgresql Fix (some of) pltcl memory usage As reported by Bill Parker, PL/Tcl did not validate some malloc() calls against NULL return. Fix by using palloc() in a new long-lived memory context instead. This allows us to simplify error handling too, by simply deleting the memory context instead of doing retail frees. There's still a lot that could be done to improve PL/Tcl's memory handling ... This is pretty ancient, so backpatch all the way back. Author: Michael Paquier and Álvaro Herrera Discussion: https://www.postgresql.org/message-id/CAFrbyQwyLDYXfBOhPfoBGqnvuZO_Y90YgqFM11T2jvnxjLFmqw@mail.gmail.com --- diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index d6b72f7d68..48a3206da1 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -2104,6 +2104,7 @@ static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) { + volatile MemoryContext plan_cxt = NULL; int nargs; CONST84 char **args; pltcl_query_desc *qdesc; @@ -2132,13 +2133,24 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, /************************************************************ * Allocate the new querydesc structure + * + * struct qdesc and subsidiary data all live in plan_cxt. Note that if the + * function is recompiled for whatever reason, permanent memory leaks + * occur. FIXME someday. ************************************************************/ - qdesc = (pltcl_query_desc *) malloc(sizeof(pltcl_query_desc)); + plan_cxt = AllocSetContextCreate(TopMemoryContext, + "PL/TCL spi_prepare query", + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); + MemoryContextSwitchTo(plan_cxt); + qdesc = (pltcl_query_desc *) palloc0(sizeof(pltcl_query_desc)); snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc); qdesc->nargs = nargs; - qdesc->argtypes = (Oid *) malloc(nargs * sizeof(Oid)); - qdesc->arginfuncs = (FmgrInfo *) malloc(nargs * sizeof(FmgrInfo)); - qdesc->argtypioparams = (Oid *) malloc(nargs * sizeof(Oid)); + qdesc->argtypes = (Oid *) palloc(nargs * sizeof(Oid)); + qdesc->arginfuncs = (FmgrInfo *) palloc(nargs * sizeof(FmgrInfo)); + qdesc->argtypioparams = (Oid *) palloc(nargs * sizeof(Oid)); + MemoryContextSwitchTo(oldcontext); /************************************************************ * Execute the prepare inside a sub-transaction, so we can cope with @@ -2166,7 +2178,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, getTypeInputInfo(typId, &typInput, &typIOParam); qdesc->argtypes[i] = typId; - perm_fmgr_info(typInput, &(qdesc->arginfuncs[i])); + fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt); qdesc->argtypioparams[i] = typIOParam; } @@ -2193,10 +2205,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, { pltcl_subtrans_abort(interp, oldcontext, oldowner); - free(qdesc->argtypes); - free(qdesc->arginfuncs); - free(qdesc->argtypioparams); - free(qdesc); + MemoryContextDelete(plan_cxt); ckfree((char *) args); return TCL_ERROR;