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

Commit59f23fe

Browse files
committed
Make plperl safe against functions that are redefined while running.
validate_plperl_function() supposed that it could free an oldplperl_proc_desc struct immediately upon detecting that it was stale.However, if a plperl function is called recursively, this could resultin deleting the struct out from under an outer invocation, leading tomisbehavior or crashes. Add a simple reference-count mechanism toensure that such structs are freed only when the last reference goesaway.Per investigation of bug #7516 from Marko Tiikkaja. I am not certainthat this error explains his report, because he says he didn't haveany recursive calls --- but it's hard to see how else it could havecrashed right there. In any case, this definitely fixes some problemsin the area.Back-patch to all active branches.
1 parent843363b commit59f23fe

File tree

3 files changed

+99
-33
lines changed

3 files changed

+99
-33
lines changed

‎src/pl/plperl/expected/plperl.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,3 +693,21 @@ $$ LANGUAGE plperl;
693693
SELECT text_scalarref();
694694
ERROR: PL/Perl function must return reference to hash or array
695695
CONTEXT: PL/Perl function "text_scalarref"
696+
-- check safe behavior when a function body is replaced during execution
697+
CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS $$
698+
spi_exec_query('CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS \'return $_[0] * 3;\' LANGUAGE plperl;');
699+
spi_exec_query('select self_modify(42) AS a');
700+
return $_[0] * 2;
701+
$$ LANGUAGE plperl;
702+
SELECT self_modify(42);
703+
self_modify
704+
-------------
705+
84
706+
(1 row)
707+
708+
SELECT self_modify(42);
709+
self_modify
710+
-------------
711+
126
712+
(1 row)
713+

‎src/pl/plperl/plperl.c

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ PG_MODULE_MAGIC;
7070
*
7171
* The plperl_interp_desc structs are kept in a Postgres hash table indexed
7272
* by userid OID, with OID 0 used for the single untrusted interpreter.
73+
* Once created, an interpreter is kept for the life of the process.
7374
*
7475
* We start out by creating a "held" interpreter, which we initialize
7576
* only as far as we can do without deciding if it will be trusted or
@@ -95,28 +96,44 @@ typedef struct plperl_interp_desc
9596

9697
/**********************************************************************
9798
* The information we cache about loaded procedures
99+
*
100+
* The refcount field counts the struct's reference from the hash table shown
101+
* below, plus one reference for each function call level that is using the
102+
* struct. We can release the struct, and the associated Perl sub, when the
103+
* refcount goes to zero.
98104
**********************************************************************/
99105
typedefstructplperl_proc_desc
100106
{
101107
char*proname;/* user name of procedure */
102-
TransactionIdfn_xmin;
108+
TransactionIdfn_xmin;/* xmin/TID of procedure's pg_proc tuple */
103109
ItemPointerDatafn_tid;
110+
intrefcount;/* reference count of this struct */
111+
SV*reference;/* CODE reference for Perl sub */
104112
plperl_interp_desc*interp;/* interpreter it's created in */
105-
boolfn_readonly;
106-
boollanpltrusted;
113+
boolfn_readonly;/* is function readonly (not volatile)? */
114+
boollanpltrusted;/* is it plperl, rather than plperlu? */
107115
boolfn_retistuple;/* true, if function returns tuple */
108116
boolfn_retisset;/* true, if function returns set */
109117
boolfn_retisarray;/* true if function returns array */
118+
/* Conversion info for function's result type: */
110119
Oidresult_oid;/* Oid of result type */
111120
FmgrInforesult_in_func;/* I/O function and arg for result type */
112121
Oidresult_typioparam;
122+
/* Conversion info for function's argument types: */
113123
intnargs;
114124
FmgrInfoarg_out_func[FUNC_MAX_ARGS];
115125
boolarg_is_rowtype[FUNC_MAX_ARGS];
116126
Oidarg_arraytype[FUNC_MAX_ARGS];/* InvalidOid if not an array */
117-
SV*reference;
118127
}plperl_proc_desc;
119128

129+
#defineincrement_prodesc_refcount(prodesc) \
130+
((prodesc)->refcount++)
131+
#definedecrement_prodesc_refcount(prodesc) \
132+
do { \
133+
if (--((prodesc)->refcount) <= 0) \
134+
free_plperl_function(prodesc); \
135+
} while(0)
136+
120137
/**********************************************************************
121138
* For speedy lookup, we maintain a hash table mapping from
122139
* function OID + trigger flag + user OID to plperl_proc_desc pointers.
@@ -238,6 +255,8 @@ static void set_interp_require(bool trusted);
238255
staticDatumplperl_func_handler(PG_FUNCTION_ARGS);
239256
staticDatumplperl_trigger_handler(PG_FUNCTION_ARGS);
240257

258+
staticvoidfree_plperl_function(plperl_proc_desc*prodesc);
259+
241260
staticplperl_proc_desc*compile_plperl_function(Oidfn_oid,boolis_trigger);
242261

243262
staticSV*plperl_hash_from_tuple(HeapTupletuple,TupleDesctupdesc);
@@ -1689,19 +1708,24 @@ plperl_call_handler(PG_FUNCTION_ARGS)
16891708

16901709
PG_TRY();
16911710
{
1711+
current_call_data=NULL;
16921712
if (CALLED_AS_TRIGGER(fcinfo))
16931713
retval=PointerGetDatum(plperl_trigger_handler(fcinfo));
16941714
else
16951715
retval=plperl_func_handler(fcinfo);
16961716
}
16971717
PG_CATCH();
16981718
{
1719+
if (current_call_data&&current_call_data->prodesc)
1720+
decrement_prodesc_refcount(current_call_data->prodesc);
16991721
current_call_data=save_call_data;
17001722
activate_interpreter(oldinterp);
17011723
PG_RE_THROW();
17021724
}
17031725
PG_END_TRY();
17041726

1727+
if (current_call_data&&current_call_data->prodesc)
1728+
decrement_prodesc_refcount(current_call_data->prodesc);
17051729
current_call_data=save_call_data;
17061730
activate_interpreter(oldinterp);
17071731
returnretval;
@@ -1753,14 +1777,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
17531777
desc.nargs=0;
17541778
desc.reference=NULL;
17551779

1756-
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1757-
current_call_data->fcinfo=&fake_fcinfo;
1758-
current_call_data->prodesc=&desc;
1759-
17601780
PG_TRY();
17611781
{
17621782
SV*perlret;
17631783

1784+
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1785+
current_call_data->fcinfo=&fake_fcinfo;
1786+
current_call_data->prodesc=&desc;
1787+
/* we do not bother with refcounting the fake prodesc */
1788+
17641789
if (SPI_connect()!=SPI_OK_CONNECT)
17651790
elog(ERROR,"could not connect to SPI manager");
17661791

@@ -2154,6 +2179,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
21542179

21552180
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, false);
21562181
current_call_data->prodesc=prodesc;
2182+
increment_prodesc_refcount(prodesc);
21572183

21582184
/* Set a callback for error reporting */
21592185
pl_error_context.callback=plperl_exec_callback;
@@ -2274,6 +2300,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
22742300
/* Find or compile the function */
22752301
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, true);
22762302
current_call_data->prodesc=prodesc;
2303+
increment_prodesc_refcount(prodesc);
22772304

22782305
/* Set a callback for error reporting */
22792306
pl_error_context.callback=plperl_exec_callback;
@@ -2383,23 +2410,35 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
23832410

23842411
/* Otherwise, unlink the obsoleted entry from the hashtable ... */
23852412
proc_ptr->proc_ptr=NULL;
2386-
/* ... and throw it away */
2387-
if (prodesc->reference)
2388-
{
2389-
plperl_interp_desc*oldinterp=plperl_active_interp;
2390-
2391-
activate_interpreter(prodesc->interp);
2392-
SvREFCNT_dec(prodesc->reference);
2393-
activate_interpreter(oldinterp);
2394-
}
2395-
free(prodesc->proname);
2396-
free(prodesc);
2413+
/* ... and release the corresponding refcount, probably deleting it */
2414+
decrement_prodesc_refcount(prodesc);
23972415
}
23982416

23992417
return false;
24002418
}
24012419

24022420

2421+
staticvoid
2422+
free_plperl_function(plperl_proc_desc*prodesc)
2423+
{
2424+
Assert(prodesc->refcount <=0);
2425+
/* Release CODE reference, if we have one, from the appropriate interp */
2426+
if (prodesc->reference)
2427+
{
2428+
plperl_interp_desc*oldinterp=plperl_active_interp;
2429+
2430+
activate_interpreter(prodesc->interp);
2431+
SvREFCNT_dec(prodesc->reference);
2432+
activate_interpreter(oldinterp);
2433+
}
2434+
/* Get rid of what we conveniently can of our own structs */
2435+
/* (FmgrInfo subsidiary info will get leaked ...) */
2436+
if (prodesc->proname)
2437+
free(prodesc->proname);
2438+
free(prodesc);
2439+
}
2440+
2441+
24032442
staticplperl_proc_desc*
24042443
compile_plperl_function(Oidfn_oid,boolis_trigger)
24052444
{
@@ -2470,12 +2509,17 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
24702509
ereport(ERROR,
24712510
(errcode(ERRCODE_OUT_OF_MEMORY),
24722511
errmsg("out of memory")));
2512+
/* Initialize all fields to 0 so free_plperl_function is safe */
24732513
MemSet(prodesc,0,sizeof(plperl_proc_desc));
2514+
24742515
prodesc->proname=strdup(NameStr(procStruct->proname));
24752516
if (prodesc->proname==NULL)
2517+
{
2518+
free_plperl_function(prodesc);
24762519
ereport(ERROR,
24772520
(errcode(ERRCODE_OUT_OF_MEMORY),
24782521
errmsg("out of memory")));
2522+
}
24792523
prodesc->fn_xmin=HeapTupleHeaderGetXmin(procTup->t_data);
24802524
prodesc->fn_tid=procTup->t_self;
24812525

@@ -2490,8 +2534,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
24902534
ObjectIdGetDatum(procStruct->prolang));
24912535
if (!HeapTupleIsValid(langTup))
24922536
{
2493-
free(prodesc->proname);
2494-
free(prodesc);
2537+
free_plperl_function(prodesc);
24952538
elog(ERROR,"cache lookup failed for language %u",
24962539
procStruct->prolang);
24972540
}
@@ -2510,8 +2553,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25102553
ObjectIdGetDatum(procStruct->prorettype));
25112554
if (!HeapTupleIsValid(typeTup))
25122555
{
2513-
free(prodesc->proname);
2514-
free(prodesc);
2556+
free_plperl_function(prodesc);
25152557
elog(ERROR,"cache lookup failed for type %u",
25162558
procStruct->prorettype);
25172559
}
@@ -2525,17 +2567,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25252567
/* okay */ ;
25262568
elseif (procStruct->prorettype==TRIGGEROID)
25272569
{
2528-
free(prodesc->proname);
2529-
free(prodesc);
2570+
free_plperl_function(prodesc);
25302571
ereport(ERROR,
25312572
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25322573
errmsg("trigger functions can only be called "
25332574
"as triggers")));
25342575
}
25352576
else
25362577
{
2537-
free(prodesc->proname);
2538-
free(prodesc);
2578+
free_plperl_function(prodesc);
25392579
ereport(ERROR,
25402580
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25412581
errmsg("PL/Perl functions cannot return type %s",
@@ -2570,8 +2610,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25702610
ObjectIdGetDatum(procStruct->proargtypes.values[i]));
25712611
if (!HeapTupleIsValid(typeTup))
25722612
{
2573-
free(prodesc->proname);
2574-
free(prodesc);
2613+
free_plperl_function(prodesc);
25752614
elog(ERROR,"cache lookup failed for type %u",
25762615
procStruct->proargtypes.values[i]);
25772616
}
@@ -2581,8 +2620,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25812620
if (typeStruct->typtype==TYPTYPE_PSEUDO&&
25822621
procStruct->proargtypes.values[i]!=RECORDOID)
25832622
{
2584-
free(prodesc->proname);
2585-
free(prodesc);
2623+
free_plperl_function(prodesc);
25862624
ereport(ERROR,
25872625
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25882626
errmsg("PL/Perl functions cannot accept type %s",
@@ -2635,8 +2673,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26352673
pfree(proc_source);
26362674
if (!prodesc->reference)/* can this happen? */
26372675
{
2638-
free(prodesc->proname);
2639-
free(prodesc);
2676+
free_plperl_function(prodesc);
26402677
elog(ERROR,"could not create PL/Perl internal procedure");
26412678
}
26422679

@@ -2648,6 +2685,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26482685
proc_ptr=hash_search(plperl_proc_hash,&proc_key,
26492686
HASH_ENTER,NULL);
26502687
proc_ptr->proc_ptr=prodesc;
2688+
increment_prodesc_refcount(prodesc);
26512689
}
26522690

26532691
/* restore previous error callback */

‎src/pl/plperl/sql/plperl.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,13 @@ CREATE OR REPLACE FUNCTION text_scalarref() RETURNS text AS $$
462462
$$ LANGUAGE plperl;
463463

464464
SELECT text_scalarref();
465+
466+
-- check safe behavior when a function body is replaced during execution
467+
CREATE OR REPLACEFUNCTIONself_modify(INTEGER) RETURNSINTEGERAS $$
468+
spi_exec_query('CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS\'return $_[0] * 3;\' LANGUAGE plperl;');
469+
spi_exec_query('select self_modify(42) AS a');
470+
return $_[0]*2;
471+
$$ LANGUAGE plperl;
472+
473+
SELECT self_modify(42);
474+
SELECT self_modify(42);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp