Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit18c6dd8

Browse files
committed
Eliminate memory leaks in plperl's spi_prepare() function.
Careless use of TopMemoryContext for I/O function data meant that repeateduse of spi_prepare and spi_freeplan would leak memory at the session level,as per report from Christian Schröder. In addition, spi_prepareleaked a lot of transient data within the current plperl function's SPIProc context, which would be a problem for repeated use of spi_preparewithin a single plperl function call; and it wasn't terribly carefulabout releasing permanent allocations in event of an error, either.In passing, clean up some copy-and-pasteos in query-lookup error messages.Alex Hunsaker and Tom Lane
1 parent0c54796 commit18c6dd8

File tree

1 file changed

+72
-44
lines changed

1 file changed

+72
-44
lines changed

‎src/pl/plperl/plperl.c

Lines changed: 72 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ typedef struct plperl_call_data
180180
typedefstructplperl_query_desc
181181
{
182182
charqname[24];
183+
MemoryContextplan_cxt;/* context holding this struct */
183184
void*plan;
184185
intnargs;
185186
Oid*argtypes;
@@ -2716,33 +2717,57 @@ plperl_spi_cursor_close(char *cursor)
27162717
SV*
27172718
plperl_spi_prepare(char*query,intargc,SV**argv)
27182719
{
2719-
plperl_query_desc*qdesc;
2720-
plperl_query_entry*hash_entry;
2721-
boolfound;
2722-
void*plan;
2723-
inti;
2724-
2720+
void*volatileplan=NULL;
2721+
volatileMemoryContextplan_cxt=NULL;
2722+
plperl_query_desc*volatileqdesc=NULL;
2723+
plperl_query_entry*volatilehash_entry=NULL;
27252724
MemoryContextoldcontext=CurrentMemoryContext;
27262725
ResourceOwneroldowner=CurrentResourceOwner;
2726+
MemoryContextwork_cxt;
2727+
boolfound;
2728+
inti;
27272729

27282730
check_spi_usage_allowed();
27292731

27302732
BeginInternalSubTransaction(NULL);
27312733
MemoryContextSwitchTo(oldcontext);
27322734

2733-
/************************************************************
2734-
* Allocate the new querydesc structure
2735-
************************************************************/
2736-
qdesc= (plperl_query_desc*)malloc(sizeof(plperl_query_desc));
2737-
MemSet(qdesc,0,sizeof(plperl_query_desc));
2738-
snprintf(qdesc->qname,sizeof(qdesc->qname),"%p",qdesc);
2739-
qdesc->nargs=argc;
2740-
qdesc->argtypes= (Oid*)malloc(argc*sizeof(Oid));
2741-
qdesc->arginfuncs= (FmgrInfo*)malloc(argc*sizeof(FmgrInfo));
2742-
qdesc->argtypioparams= (Oid*)malloc(argc*sizeof(Oid));
2743-
27442735
PG_TRY();
27452736
{
2737+
CHECK_FOR_INTERRUPTS();
2738+
2739+
/************************************************************
2740+
* Allocate the new querydesc structure
2741+
*
2742+
* The qdesc struct, as well as all its subsidiary data, lives in its
2743+
* plan_cxt. But note that the SPIPlan does not.
2744+
************************************************************/
2745+
plan_cxt=AllocSetContextCreate(TopMemoryContext,
2746+
"PL/Perl spi_prepare query",
2747+
ALLOCSET_SMALL_MINSIZE,
2748+
ALLOCSET_SMALL_INITSIZE,
2749+
ALLOCSET_SMALL_MAXSIZE);
2750+
MemoryContextSwitchTo(plan_cxt);
2751+
qdesc= (plperl_query_desc*)palloc0(sizeof(plperl_query_desc));
2752+
snprintf(qdesc->qname,sizeof(qdesc->qname),"%p",qdesc);
2753+
qdesc->plan_cxt=plan_cxt;
2754+
qdesc->nargs=argc;
2755+
qdesc->argtypes= (Oid*)palloc(argc*sizeof(Oid));
2756+
qdesc->arginfuncs= (FmgrInfo*)palloc(argc*sizeof(FmgrInfo));
2757+
qdesc->argtypioparams= (Oid*)palloc(argc*sizeof(Oid));
2758+
MemoryContextSwitchTo(oldcontext);
2759+
2760+
/************************************************************
2761+
* Do the following work in a short-lived context so that we don't
2762+
* leak a lot of memory in the PL/Perl function's SPI Proc context.
2763+
************************************************************/
2764+
work_cxt=AllocSetContextCreate(CurrentMemoryContext,
2765+
"PL/Perl spi_prepare workspace",
2766+
ALLOCSET_DEFAULT_MINSIZE,
2767+
ALLOCSET_DEFAULT_INITSIZE,
2768+
ALLOCSET_DEFAULT_MAXSIZE);
2769+
MemoryContextSwitchTo(work_cxt);
2770+
27462771
/************************************************************
27472772
* Resolve argument type names and then look them up by oid
27482773
* in the system cache, and remember the required information
@@ -2760,7 +2785,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
27602785
getTypeInputInfo(typId,&typInput,&typIOParam);
27612786

27622787
qdesc->argtypes[i]=typId;
2763-
perm_fmgr_info(typInput,&(qdesc->arginfuncs[i]));
2788+
fmgr_info_cxt(typInput,&(qdesc->arginfuncs[i]),plan_cxt);
27642789
qdesc->argtypioparams[i]=typIOParam;
27652790
}
27662791

@@ -2788,6 +2813,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
27882813
/* Release the procCxt copy to avoid within-function memory leak */
27892814
SPI_freeplan(plan);
27902815

2816+
/************************************************************
2817+
* Insert a hashtable entry for the plan.
2818+
************************************************************/
2819+
hash_entry=hash_search(plperl_active_interp->query_hash,
2820+
qdesc->qname,
2821+
HASH_ENTER,&found);
2822+
hash_entry->query_data=qdesc;
2823+
2824+
/* Get rid of workspace */
2825+
MemoryContextDelete(work_cxt);
2826+
27912827
/* Commit the inner transaction, return to outer xact context */
27922828
ReleaseCurrentSubTransaction();
27932829
MemoryContextSwitchTo(oldcontext);
@@ -2803,16 +2839,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
28032839
{
28042840
ErrorData*edata;
28052841

2806-
free(qdesc->argtypes);
2807-
free(qdesc->arginfuncs);
2808-
free(qdesc->argtypioparams);
2809-
free(qdesc);
2810-
28112842
/* Save error info */
28122843
MemoryContextSwitchTo(oldcontext);
28132844
edata=CopyErrorData();
28142845
FlushErrorState();
28152846

2847+
/* Drop anything we managed to allocate */
2848+
if (hash_entry)
2849+
hash_search(plperl_active_interp->query_hash,
2850+
qdesc->qname,
2851+
HASH_REMOVE,NULL);
2852+
if (plan_cxt)
2853+
MemoryContextDelete(plan_cxt);
2854+
if (plan)
2855+
SPI_freeplan(plan);
2856+
28162857
/* Abort the inner transaction */
28172858
RollbackAndReleaseCurrentSubTransaction();
28182859
MemoryContextSwitchTo(oldcontext);
@@ -2834,14 +2875,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
28342875
PG_END_TRY();
28352876

28362877
/************************************************************
2837-
* Insert a hashtable entry for the plan and return
2838-
* the key to the caller.
2878+
* Return the query's hash key to the caller.
28392879
************************************************************/
2840-
2841-
hash_entry=hash_search(plperl_active_interp->query_hash,qdesc->qname,
2842-
HASH_ENTER,&found);
2843-
hash_entry->query_data=qdesc;
2844-
28452880
returnnewSVstring(qdesc->qname);
28462881
}
28472882

@@ -2876,16 +2911,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
28762911
/************************************************************
28772912
* Fetch the saved plan descriptor, see if it's o.k.
28782913
************************************************************/
2879-
28802914
hash_entry=hash_search(plperl_active_interp->query_hash,query,
28812915
HASH_FIND,NULL);
28822916
if (hash_entry==NULL)
28832917
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
28842918

28852919
qdesc=hash_entry->query_data;
2886-
28872920
if (qdesc==NULL)
2888-
elog(ERROR,"spi_exec_prepared:panic -plperl query_hash value vanished");
2921+
elog(ERROR,"spi_exec_prepared: plperl query_hash value vanished");
28892922

28902923
if (qdesc->nargs!=argc)
28912924
elog(ERROR,"spi_exec_prepared: expected %d argument(s), %d passed",
@@ -3023,12 +3056,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
30233056
hash_entry=hash_search(plperl_active_interp->query_hash,query,
30243057
HASH_FIND,NULL);
30253058
if (hash_entry==NULL)
3026-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3059+
elog(ERROR,"spi_query_prepared: Invalid prepared query passed");
30273060

30283061
qdesc=hash_entry->query_data;
3029-
30303062
if (qdesc==NULL)
3031-
elog(ERROR,"spi_query_prepared:panic -plperl query_hash value vanished");
3063+
elog(ERROR,"spi_query_prepared: plperl query_hash value vanished");
30323064

30333065
if (qdesc->nargs!=argc)
30343066
elog(ERROR,"spi_query_prepared: expected %d argument(s), %d passed",
@@ -3139,12 +3171,12 @@ plperl_spi_freeplan(char *query)
31393171
hash_entry=hash_search(plperl_active_interp->query_hash,query,
31403172
HASH_FIND,NULL);
31413173
if (hash_entry==NULL)
3142-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3174+
elog(ERROR,"spi_freeplan: Invalid prepared query passed");
31433175

31443176
qdesc=hash_entry->query_data;
3145-
31463177
if (qdesc==NULL)
3147-
elog(ERROR,"spi_exec_freeplan: panic - plperl query_hash value vanished");
3178+
elog(ERROR,"spi_freeplan: plperl query_hash value vanished");
3179+
plan=qdesc->plan;
31483180

31493181
/*
31503182
* free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3153,11 +3185,7 @@ plperl_spi_freeplan(char *query)
31533185
hash_search(plperl_active_interp->query_hash,query,
31543186
HASH_REMOVE,NULL);
31553187

3156-
plan=qdesc->plan;
3157-
free(qdesc->argtypes);
3158-
free(qdesc->arginfuncs);
3159-
free(qdesc->argtypioparams);
3160-
free(qdesc);
3188+
MemoryContextDelete(qdesc->plan_cxt);
31613189

31623190
SPI_freeplan(plan);
31633191
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp