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

Commitb2da7c8

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 parentf5185db commitb2da7c8

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
@@ -182,6 +182,7 @@ typedef struct plperl_call_data
182182
typedefstructplperl_query_desc
183183
{
184184
charqname[24];
185+
MemoryContextplan_cxt;/* context holding this struct */
185186
void*plan;
186187
intnargs;
187188
Oid*argtypes;
@@ -3199,33 +3200,57 @@ plperl_spi_cursor_close(char *cursor)
31993200
SV*
32003201
plperl_spi_prepare(char*query,intargc,SV**argv)
32013202
{
3202-
plperl_query_desc*qdesc;
3203-
plperl_query_entry*hash_entry;
3204-
boolfound;
3205-
void*plan;
3206-
inti;
3207-
3203+
void*volatileplan=NULL;
3204+
volatileMemoryContextplan_cxt=NULL;
3205+
plperl_query_desc*volatileqdesc=NULL;
3206+
plperl_query_entry*volatilehash_entry=NULL;
32083207
MemoryContextoldcontext=CurrentMemoryContext;
32093208
ResourceOwneroldowner=CurrentResourceOwner;
3209+
MemoryContextwork_cxt;
3210+
boolfound;
3211+
inti;
32103212

32113213
check_spi_usage_allowed();
32123214

32133215
BeginInternalSubTransaction(NULL);
32143216
MemoryContextSwitchTo(oldcontext);
32153217

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

32483273
qdesc->argtypes[i]=typId;
3249-
perm_fmgr_info(typInput,&(qdesc->arginfuncs[i]));
3274+
fmgr_info_cxt(typInput,&(qdesc->arginfuncs[i]),plan_cxt);
32503275
qdesc->argtypioparams[i]=typIOParam;
32513276
}
32523277

@@ -3274,6 +3299,17 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32743299
/* Release the procCxt copy to avoid within-function memory leak */
32753300
SPI_freeplan(plan);
32763301

3302+
/************************************************************
3303+
* Insert a hashtable entry for the plan.
3304+
************************************************************/
3305+
hash_entry=hash_search(plperl_active_interp->query_hash,
3306+
qdesc->qname,
3307+
HASH_ENTER,&found);
3308+
hash_entry->query_data=qdesc;
3309+
3310+
/* Get rid of workspace */
3311+
MemoryContextDelete(work_cxt);
3312+
32773313
/* Commit the inner transaction, return to outer xact context */
32783314
ReleaseCurrentSubTransaction();
32793315
MemoryContextSwitchTo(oldcontext);
@@ -3289,16 +3325,21 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
32893325
{
32903326
ErrorData*edata;
32913327

3292-
free(qdesc->argtypes);
3293-
free(qdesc->arginfuncs);
3294-
free(qdesc->argtypioparams);
3295-
free(qdesc);
3296-
32973328
/* Save error info */
32983329
MemoryContextSwitchTo(oldcontext);
32993330
edata=CopyErrorData();
33003331
FlushErrorState();
33013332

3333+
/* Drop anything we managed to allocate */
3334+
if (hash_entry)
3335+
hash_search(plperl_active_interp->query_hash,
3336+
qdesc->qname,
3337+
HASH_REMOVE,NULL);
3338+
if (plan_cxt)
3339+
MemoryContextDelete(plan_cxt);
3340+
if (plan)
3341+
SPI_freeplan(plan);
3342+
33023343
/* Abort the inner transaction */
33033344
RollbackAndReleaseCurrentSubTransaction();
33043345
MemoryContextSwitchTo(oldcontext);
@@ -3320,14 +3361,8 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
33203361
PG_END_TRY();
33213362

33223363
/************************************************************
3323-
* Insert a hashtable entry for the plan and return
3324-
* the key to the caller.
3364+
* Return the query's hash key to the caller.
33253365
************************************************************/
3326-
3327-
hash_entry=hash_search(plperl_active_interp->query_hash,qdesc->qname,
3328-
HASH_ENTER,&found);
3329-
hash_entry->query_data=qdesc;
3330-
33313366
returncstr2sv(qdesc->qname);
33323367
}
33333368

@@ -3362,16 +3397,14 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
33623397
/************************************************************
33633398
* Fetch the saved plan descriptor, see if it's o.k.
33643399
************************************************************/
3365-
33663400
hash_entry=hash_search(plperl_active_interp->query_hash,query,
33673401
HASH_FIND,NULL);
33683402
if (hash_entry==NULL)
33693403
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
33703404

33713405
qdesc=hash_entry->query_data;
3372-
33733406
if (qdesc==NULL)
3374-
elog(ERROR,"spi_exec_prepared:panic -plperl query_hash value vanished");
3407+
elog(ERROR,"spi_exec_prepared: plperl query_hash value vanished");
33753408

33763409
if (qdesc->nargs!=argc)
33773410
elog(ERROR,"spi_exec_prepared: expected %d argument(s), %d passed",
@@ -3503,12 +3536,11 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv)
35033536
hash_entry=hash_search(plperl_active_interp->query_hash,query,
35043537
HASH_FIND,NULL);
35053538
if (hash_entry==NULL)
3506-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3539+
elog(ERROR,"spi_query_prepared: Invalid prepared query passed");
35073540

35083541
qdesc=hash_entry->query_data;
3509-
35103542
if (qdesc==NULL)
3511-
elog(ERROR,"spi_query_prepared:panic -plperl query_hash value vanished");
3543+
elog(ERROR,"spi_query_prepared: plperl query_hash value vanished");
35123544

35133545
if (qdesc->nargs!=argc)
35143546
elog(ERROR,"spi_query_prepared: expected %d argument(s), %d passed",
@@ -3613,12 +3645,12 @@ plperl_spi_freeplan(char *query)
36133645
hash_entry=hash_search(plperl_active_interp->query_hash,query,
36143646
HASH_FIND,NULL);
36153647
if (hash_entry==NULL)
3616-
elog(ERROR,"spi_exec_prepared: Invalid prepared query passed");
3648+
elog(ERROR,"spi_freeplan: Invalid prepared query passed");
36173649

36183650
qdesc=hash_entry->query_data;
3619-
36203651
if (qdesc==NULL)
3621-
elog(ERROR,"spi_exec_freeplan: panic - plperl query_hash value vanished");
3652+
elog(ERROR,"spi_freeplan: plperl query_hash value vanished");
3653+
plan=qdesc->plan;
36223654

36233655
/*
36243656
* free all memory before SPI_freeplan, so if it dies, nothing will be
@@ -3627,11 +3659,7 @@ plperl_spi_freeplan(char *query)
36273659
hash_search(plperl_active_interp->query_hash,query,
36283660
HASH_REMOVE,NULL);
36293661

3630-
plan=qdesc->plan;
3631-
free(qdesc->argtypes);
3632-
free(qdesc->arginfuncs);
3633-
free(qdesc->argtypioparams);
3634-
free(qdesc);
3662+
MemoryContextDelete(qdesc->plan_cxt);
36353663

36363664
SPI_freeplan(plan);
36373665
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp