Fix (some of) pltcl memory usage
authorAlvaro Herrera
Mon, 20 Jul 2015 12:18:08 +0000 (14:18 +0200)
committerAlvaro Herrera
Mon, 20 Jul 2015 12:18:08 +0000 (14:18 +0200)
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

src/pl/tcl/pltcl.c

index 9fdfc37f04248a5493bb0e5c4ff1a83b63d7853f..0c8ed7ed201faae2b02c5000c6d9980d45ef6c2b 100644 (file)
@@ -2039,6 +2039,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;
@@ -2067,13 +2068,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
@@ -2101,7 +2113,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;
        }
 
@@ -2128,10 +2140,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;