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

Commita4d3a50

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 parentcd7d00a commita4d3a50

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
@@ -184,6 +184,7 @@ typedef struct plperl_call_data
184184
typedefstructplperl_query_desc
185185
{
186186
charqname[24];
187+
MemoryContextplan_cxt;/* context holding this struct */
187188
SPIPlanPtrplan;
188189
intnargs;
189190
Oid*argtypes;
@@ -3209,33 +3210,57 @@ plperl_spi_cursor_close(char *cursor)
32093210
SV*
32103211
plperl_spi_prepare(char*query,intargc,SV**argv)
32113212
{
3212-
plperl_query_desc*qdesc;
3213-
plperl_query_entry*hash_entry;
3214-
boolfound;
3215-
SPIPlanPtrplan;
3216-
inti;
3217-
3213+
volatileSPIPlanPtrplan=NULL;
3214+
volatileMemoryContextplan_cxt=NULL;
3215+
plperl_query_desc*volatileqdesc=NULL;
3216+
plperl_query_entry*volatilehash_entry=NULL;
32183217
MemoryContextoldcontext=CurrentMemoryContext;
32193218
ResourceOwneroldowner=CurrentResourceOwner;
3219+
MemoryContextwork_cxt;
3220+
boolfound;
3221+
inti;
32203222

32213223
check_spi_usage_allowed();
32223224

32233225
BeginInternalSubTransaction(NULL);
32243226
MemoryContextSwitchTo(oldcontext);
32253227

3226-
/************************************************************
3227-
* Allocate the new querydesc structure
3228-
************************************************************/
3229-
qdesc= (plperl_query_desc*)malloc(sizeof(plperl_query_desc));
3230-
MemSet(qdesc,0,sizeof(plperl_query_desc));
3231-
snprintf(qdesc->qname,sizeof(qdesc->qname),"%p",qdesc);
3232-
qdesc->nargs=argc;
3233-
qdesc->argtypes= (Oid*)malloc(argc*sizeof(Oid));
3234-
qdesc->arginfuncs= (FmgrInfo*)malloc(argc*sizeof(FmgrInfo));
3235-
qdesc->argtypioparams= (Oid*)malloc(argc*sizeof(Oid));
3236-
32373228
PG_TRY();
32383229
{
3230+
CHECK_FOR_INTERRUPTS();
3231+
3232+
/************************************************************
3233+
* Allocate the new querydesc structure
3234+
*
3235+
* The qdesc struct, as well as all its subsidiary data, lives in its
3236+
* plan_cxt. But note that the SPIPlan does not.
3237+
************************************************************/
3238+
plan_cxt=AllocSetContextCreate(TopMemoryContext,
3239+
"PL/Perl spi_prepare query",
3240+
ALLOCSET_SMALL_MINSIZE,
3241+
ALLOCSET_SMALL_INITSIZE,
3242+
ALLOCSET_SMALL_MAXSIZE);
3243+
MemoryContextSwitchTo(plan_cxt);
3244+
qdesc= (plperl_query_desc*)palloc0(sizeof(plperl_query_desc));
3245+
snprintf(qdesc->qname,sizeof(qdesc->qname),"%p",qdesc);
3246+
qdesc->plan_cxt=plan_cxt;
3247+
qdesc->nargs=argc;
3248+
qdesc->argtypes= (Oid*)palloc(argc*sizeof(Oid));
3249+
qdesc->arginfuncs= (FmgrInfo*)palloc(argc*sizeof(FmgrInfo));
3250+
qdesc->argtypioparams= (Oid*)palloc(argc*sizeof(Oid));
3251+
MemoryContextSwitchTo(oldcontext);
3252+
3253+
/************************************************************
3254+
* Do the following work in a short-lived context so that we don't
3255+
* leak a lot of memory in the PL/Perl function's SPI Proc context.
3256+
************************************************************/
3257+
work_cxt=AllocSetContextCreate(CurrentMemoryContext,
3258+
"PL/Perl spi_prepare workspace",
3259+
ALLOCSET_DEFAULT_MINSIZE,
3260+
ALLOCSET_DEFAULT_INITSIZE,
3261+
ALLOCSET_DEFAULT_MAXSIZE);
3262+
MemoryContextSwitchTo(work_cxt);
3263+
32393264
/************************************************************
32403265
* Resolve argument type names and then look them up by oid
32413266
* in the system cache, and remember the required information
@@ -3256,7 +3281,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32563281
getTypeInputInfo(typId,&typInput,&typIOParam);
32573282

32583283
qdesc->argtypes[i]=typId;
3259-
perm_fmgr_info(typInput,&(qdesc->arginfuncs[i]));
3284+
fmgr_info_cxt(typInput,&(qdesc->arginfuncs[i]),plan_cxt);
32603285
qdesc->argtypioparams[i]=typIOParam;
32613286
}
32623287

@@ -3280,6 +3305,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32803305
elog(ERROR,"SPI_keepplan() failed");
32813306
qdesc->plan=plan;
32823307

3308+
/************************************************************
3309+
* Insert a hashtable entry for the plan.
3310+
************************************************************/
3311+
hash_entry=hash_search(plperl_active_interp->query_hash,
3312+
qdesc->qname,
3313+
HASH_ENTER,&found);
3314+
hash_entry->query_data=qdesc;
3315+
3316+
/* Get rid of workspace */
3317+
MemoryContextDelete(work_cxt);
3318+
32833319
/* Commit the inner transaction, return to outer xact context */
32843320
ReleaseCurrentSubTransaction();
32853321
MemoryContextSwitchTo(oldcontext);
@@ -3295,16 +3331,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32953331
{
32963332
ErrorData*edata;
32973333

3298-
free(qdesc->argtypes);
3299-
free(qdesc->arginfuncs);
3300-
free(qdesc->argtypioparams);
3301-
free(qdesc);
3302-
33033334
/* Save error info */
33043335
MemoryContextSwitchTo(oldcontext);
33053336
edata=CopyErrorData();
33063337
FlushErrorState();
33073338

3339+
/* Drop anything we managed to allocate */
3340+
if (hash_entry)
3341+
hash_search(plperl_active_interp->query_hash,
3342+
qdesc->qname,
3343+
HASH_REMOVE,NULL);
3344+
if (plan_cxt)
3345+
MemoryContextDelete(plan_cxt);
3346+
if (plan)
3347+
SPI_freeplan(plan);
3348+
33083349
/* Abort the inner transaction */
33093350
RollbackAndReleaseCurrentSubTransaction();
33103351
MemoryContextSwitchTo(oldcontext);
@@ -3326,14 +3367,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
33263367
PG_END_TRY();
33273368

33283369
/************************************************************
3329-
* Insert a hashtable entry for the plan and return
3330-
* the key to the caller.
3370+
* Return the query's hash key to the caller.
33313371
************************************************************/
3332-
3333-
hash_entry=hash_search(plperl_active_interp->query_hash,qdesc->qname,
3334-
HASH_ENTER,&found);
3335-
hash_entry->query_data=qdesc;
3336-
33373372
returncstr2sv(qdesc->qname);
33383373
}
33393374

@@ -3368,16 +3403,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
33683403
/************************************************************
33693404
* Fetch the saved plan descriptor, see if it's o.k.
33703405
************************************************************/
3371-
33723406
hash_entry=hash_search(plperl_active_interp->query_hash,query,
33733407
HASH_FIND,NULL);
33743408
if (hash_entry==NULL)
33753409
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
33763410

33773411
qdesc=hash_entry->query_data;
3378-
33793412
if (qdesc==NULL)
3380-
elog(ERROR,"spi_exec_prepared:panic -plperl query_hash value vanished");
3413+
elog(ERROR,"spi_exec_prepared: plperl query_hash value vanished");
33813414

33823415
if (qdesc->nargs!=argc)
33833416
elog(ERROR,"spi_exec_prepared: expected %d argument(s), %d passed",
@@ -3509,12 +3542,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
35093542
hash_entry=hash_search(plperl_active_interp->query_hash,query,
35103543
HASH_FIND,NULL);
35113544
if (hash_entry==NULL)
3512-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3545+
elog(ERROR,"spi_query_prepared: Invalid prepared query passed");
35133546

35143547
qdesc=hash_entry->query_data;
3515-
35163548
if (qdesc==NULL)
3517-
elog(ERROR,"spi_query_prepared:panic -plperl query_hash value vanished");
3549+
elog(ERROR,"spi_query_prepared: plperl query_hash value vanished");
35183550

35193551
if (qdesc->nargs!=argc)
35203552
elog(ERROR,"spi_query_prepared: expected %d argument(s), %d passed",
@@ -3619,12 +3651,12 @@ plperl_spi_freeplan(char *query)
36193651
hash_entry=hash_search(plperl_active_interp->query_hash,query,
36203652
HASH_FIND,NULL);
36213653
if (hash_entry==NULL)
3622-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3654+
elog(ERROR,"spi_freeplan: Invalid prepared query passed");
36233655

36243656
qdesc=hash_entry->query_data;
3625-
36263657
if (qdesc==NULL)
3627-
elog(ERROR,"spi_exec_freeplan: panic - plperl query_hash value vanished");
3658+
elog(ERROR,"spi_freeplan: plperl query_hash value vanished");
3659+
plan=qdesc->plan;
36283660

36293661
/*
36303662
* free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3633,11 +3665,7 @@ plperl_spi_freeplan(char *query)
36333665
hash_search(plperl_active_interp->query_hash,query,
36343666
HASH_REMOVE,NULL);
36353667

3636-
plan=qdesc->plan;
3637-
free(qdesc->argtypes);
3638-
free(qdesc->arginfuncs);
3639-
free(qdesc->argtypioparams);
3640-
free(qdesc);
3668+
MemoryContextDelete(qdesc->plan_cxt);
36413669

36423670
SPI_freeplan(plan);
36433671
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp