Skip to content

Commit 4c11967

Browse files
committed
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
1 parent cdf596b commit 4c11967

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

src/pl/tcl/pltcl.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,7 @@ static int
20222022
pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
20232023
int argc, CONST84 char *argv[])
20242024
{
2025+
volatile MemoryContext plan_cxt = NULL;
20252026
int nargs;
20262027
CONST84 char **args;
20272028
pltcl_query_desc *qdesc;
@@ -2051,13 +2052,24 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
20512052

20522053
/************************************************************
20532054
* Allocate the new querydesc structure
2055+
*
2056+
* struct qdesc and subsidiary data all live in plan_cxt. Note that if the
2057+
* function is recompiled for whatever reason, permanent memory leaks
2058+
* occur. FIXME someday.
20542059
************************************************************/
2055-
qdesc = (pltcl_query_desc *) malloc(sizeof(pltcl_query_desc));
2060+
plan_cxt = AllocSetContextCreate(TopMemoryContext,
2061+
"PL/TCL spi_prepare query",
2062+
ALLOCSET_SMALL_MINSIZE,
2063+
ALLOCSET_SMALL_INITSIZE,
2064+
ALLOCSET_SMALL_MAXSIZE);
2065+
MemoryContextSwitchTo(plan_cxt);
2066+
qdesc = (pltcl_query_desc *) palloc0(sizeof(pltcl_query_desc));
20562067
snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
20572068
qdesc->nargs = nargs;
2058-
qdesc->argtypes = (Oid *) malloc(nargs * sizeof(Oid));
2059-
qdesc->arginfuncs = (FmgrInfo *) malloc(nargs * sizeof(FmgrInfo));
2060-
qdesc->argtypioparams = (Oid *) malloc(nargs * sizeof(Oid));
2069+
qdesc->argtypes = (Oid *) palloc(nargs * sizeof(Oid));
2070+
qdesc->arginfuncs = (FmgrInfo *) palloc(nargs * sizeof(FmgrInfo));
2071+
qdesc->argtypioparams = (Oid *) palloc(nargs * sizeof(Oid));
2072+
MemoryContextSwitchTo(oldcontext);
20612073

20622074
/************************************************************
20632075
* Execute the prepare inside a sub-transaction, so we can cope with
@@ -2085,7 +2097,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
20852097
getTypeInputInfo(typId, &typInput, &typIOParam);
20862098

20872099
qdesc->argtypes[i] = typId;
2088-
perm_fmgr_info(typInput, &(qdesc->arginfuncs[i]));
2100+
fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
20892101
qdesc->argtypioparams[i] = typIOParam;
20902102
}
20912103

@@ -2116,10 +2128,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
21162128
{
21172129
pltcl_subtrans_abort(interp, oldcontext, oldowner);
21182130

2119-
free(qdesc->argtypes);
2120-
free(qdesc->arginfuncs);
2121-
free(qdesc->argtypioparams);
2122-
free(qdesc);
2131+
MemoryContextDelete(plan_cxt);
21232132
ckfree((char *) args);
21242133

21252134
return TCL_ERROR;

0 commit comments

Comments
 (0)