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

Commitef06dca

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 parent1e21450 commitef06dca

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
@@ -68,6 +68,7 @@ PG_MODULE_MAGIC;
6868
*
6969
* The plperl_interp_desc structs are kept in a Postgres hash table indexed
7070
* by userid OID, with OID 0 used for the single untrusted interpreter.
71+
* Once created, an interpreter is kept for the life of the process.
7172
*
7273
* We start out by creating a "held" interpreter, which we initialize
7374
* only as far as we can do without deciding if it will be trusted or
@@ -93,28 +94,44 @@ typedef struct plperl_interp_desc
9394

9495
/**********************************************************************
9596
* The information we cache about loaded procedures
97+
*
98+
* The refcount field counts the struct's reference from the hash table shown
99+
* below, plus one reference for each function call level that is using the
100+
* struct. We can release the struct, and the associated Perl sub, when the
101+
* refcount goes to zero.
96102
**********************************************************************/
97103
typedefstructplperl_proc_desc
98104
{
99105
char*proname;/* user name of procedure */
100-
TransactionIdfn_xmin;
106+
TransactionIdfn_xmin;/* xmin/TID of procedure's pg_proc tuple */
101107
ItemPointerDatafn_tid;
108+
intrefcount;/* reference count of this struct */
109+
SV*reference;/* CODE reference for Perl sub */
102110
plperl_interp_desc*interp;/* interpreter it's created in */
103-
boolfn_readonly;
104-
boollanpltrusted;
111+
boolfn_readonly;/* is function readonly (not volatile)? */
112+
boollanpltrusted;/* is it plperl, rather than plperlu? */
105113
boolfn_retistuple;/* true, if function returns tuple */
106114
boolfn_retisset;/* true, if function returns set */
107115
boolfn_retisarray;/* true if function returns array */
116+
/* Conversion info for function's result type: */
108117
Oidresult_oid;/* Oid of result type */
109118
FmgrInforesult_in_func;/* I/O function and arg for result type */
110119
Oidresult_typioparam;
120+
/* Conversion info for function's argument types: */
111121
intnargs;
112122
FmgrInfoarg_out_func[FUNC_MAX_ARGS];
113123
boolarg_is_rowtype[FUNC_MAX_ARGS];
114124
Oidarg_arraytype[FUNC_MAX_ARGS];/* InvalidOid if not an array */
115-
SV*reference;
116125
}plperl_proc_desc;
117126

127+
#defineincrement_prodesc_refcount(prodesc) \
128+
((prodesc)->refcount++)
129+
#definedecrement_prodesc_refcount(prodesc) \
130+
do { \
131+
if (--((prodesc)->refcount) <= 0) \
132+
free_plperl_function(prodesc); \
133+
} while(0)
134+
118135
/**********************************************************************
119136
* For speedy lookup, we maintain a hash table mapping from
120137
* function OID + trigger flag + user OID to plperl_proc_desc pointers.
@@ -236,6 +253,8 @@ static void set_interp_require(bool trusted);
236253
staticDatumplperl_func_handler(PG_FUNCTION_ARGS);
237254
staticDatumplperl_trigger_handler(PG_FUNCTION_ARGS);
238255

256+
staticvoidfree_plperl_function(plperl_proc_desc*prodesc);
257+
239258
staticplperl_proc_desc*compile_plperl_function(Oidfn_oid,boolis_trigger);
240259

241260
staticSV*plperl_hash_from_tuple(HeapTupletuple,TupleDesctupdesc);
@@ -1679,19 +1698,24 @@ plperl_call_handler(PG_FUNCTION_ARGS)
16791698

16801699
PG_TRY();
16811700
{
1701+
current_call_data=NULL;
16821702
if (CALLED_AS_TRIGGER(fcinfo))
16831703
retval=PointerGetDatum(plperl_trigger_handler(fcinfo));
16841704
else
16851705
retval=plperl_func_handler(fcinfo);
16861706
}
16871707
PG_CATCH();
16881708
{
1709+
if (current_call_data&&current_call_data->prodesc)
1710+
decrement_prodesc_refcount(current_call_data->prodesc);
16891711
current_call_data=save_call_data;
16901712
activate_interpreter(oldinterp);
16911713
PG_RE_THROW();
16921714
}
16931715
PG_END_TRY();
16941716

1717+
if (current_call_data&&current_call_data->prodesc)
1718+
decrement_prodesc_refcount(current_call_data->prodesc);
16951719
current_call_data=save_call_data;
16961720
activate_interpreter(oldinterp);
16971721
returnretval;
@@ -1743,14 +1767,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
17431767
desc.nargs=0;
17441768
desc.reference=NULL;
17451769

1746-
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1747-
current_call_data->fcinfo=&fake_fcinfo;
1748-
current_call_data->prodesc=&desc;
1749-
17501770
PG_TRY();
17511771
{
17521772
SV*perlret;
17531773

1774+
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1775+
current_call_data->fcinfo=&fake_fcinfo;
1776+
current_call_data->prodesc=&desc;
1777+
/* we do not bother with refcounting the fake prodesc */
1778+
17541779
if (SPI_connect()!=SPI_OK_CONNECT)
17551780
elog(ERROR,"could not connect to SPI manager");
17561781

@@ -2144,6 +2169,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
21442169

21452170
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, false);
21462171
current_call_data->prodesc=prodesc;
2172+
increment_prodesc_refcount(prodesc);
21472173

21482174
/* Set a callback for error reporting */
21492175
pl_error_context.callback=plperl_exec_callback;
@@ -2264,6 +2290,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
22642290
/* Find or compile the function */
22652291
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, true);
22662292
current_call_data->prodesc=prodesc;
2293+
increment_prodesc_refcount(prodesc);
22672294

22682295
/* Set a callback for error reporting */
22692296
pl_error_context.callback=plperl_exec_callback;
@@ -2373,23 +2400,35 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
23732400

23742401
/* Otherwise, unlink the obsoleted entry from the hashtable ... */
23752402
proc_ptr->proc_ptr=NULL;
2376-
/* ... and throw it away */
2377-
if (prodesc->reference)
2378-
{
2379-
plperl_interp_desc*oldinterp=plperl_active_interp;
2380-
2381-
activate_interpreter(prodesc->interp);
2382-
SvREFCNT_dec(prodesc->reference);
2383-
activate_interpreter(oldinterp);
2384-
}
2385-
free(prodesc->proname);
2386-
free(prodesc);
2403+
/* ... and release the corresponding refcount, probably deleting it */
2404+
decrement_prodesc_refcount(prodesc);
23872405
}
23882406

23892407
return false;
23902408
}
23912409

23922410

2411+
staticvoid
2412+
free_plperl_function(plperl_proc_desc*prodesc)
2413+
{
2414+
Assert(prodesc->refcount <=0);
2415+
/* Release CODE reference, if we have one, from the appropriate interp */
2416+
if (prodesc->reference)
2417+
{
2418+
plperl_interp_desc*oldinterp=plperl_active_interp;
2419+
2420+
activate_interpreter(prodesc->interp);
2421+
SvREFCNT_dec(prodesc->reference);
2422+
activate_interpreter(oldinterp);
2423+
}
2424+
/* Get rid of what we conveniently can of our own structs */
2425+
/* (FmgrInfo subsidiary info will get leaked ...) */
2426+
if (prodesc->proname)
2427+
free(prodesc->proname);
2428+
free(prodesc);
2429+
}
2430+
2431+
23932432
staticplperl_proc_desc*
23942433
compile_plperl_function(Oidfn_oid,boolis_trigger)
23952434
{
@@ -2460,12 +2499,17 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
24602499
ereport(ERROR,
24612500
(errcode(ERRCODE_OUT_OF_MEMORY),
24622501
errmsg("out of memory")));
2502+
/* Initialize all fields to 0 so free_plperl_function is safe */
24632503
MemSet(prodesc,0,sizeof(plperl_proc_desc));
2504+
24642505
prodesc->proname=strdup(NameStr(procStruct->proname));
24652506
if (prodesc->proname==NULL)
2507+
{
2508+
free_plperl_function(prodesc);
24662509
ereport(ERROR,
24672510
(errcode(ERRCODE_OUT_OF_MEMORY),
24682511
errmsg("out of memory")));
2512+
}
24692513
prodesc->fn_xmin=HeapTupleHeaderGetXmin(procTup->t_data);
24702514
prodesc->fn_tid=procTup->t_self;
24712515

@@ -2480,8 +2524,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
24802524
ObjectIdGetDatum(procStruct->prolang));
24812525
if (!HeapTupleIsValid(langTup))
24822526
{
2483-
free(prodesc->proname);
2484-
free(prodesc);
2527+
free_plperl_function(prodesc);
24852528
elog(ERROR,"cache lookup failed for language %u",
24862529
procStruct->prolang);
24872530
}
@@ -2500,8 +2543,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25002543
ObjectIdGetDatum(procStruct->prorettype));
25012544
if (!HeapTupleIsValid(typeTup))
25022545
{
2503-
free(prodesc->proname);
2504-
free(prodesc);
2546+
free_plperl_function(prodesc);
25052547
elog(ERROR,"cache lookup failed for type %u",
25062548
procStruct->prorettype);
25072549
}
@@ -2515,17 +2557,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25152557
/* okay */ ;
25162558
elseif (procStruct->prorettype==TRIGGEROID)
25172559
{
2518-
free(prodesc->proname);
2519-
free(prodesc);
2560+
free_plperl_function(prodesc);
25202561
ereport(ERROR,
25212562
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25222563
errmsg("trigger functions can only be called "
25232564
"as triggers")));
25242565
}
25252566
else
25262567
{
2527-
free(prodesc->proname);
2528-
free(prodesc);
2568+
free_plperl_function(prodesc);
25292569
ereport(ERROR,
25302570
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25312571
errmsg("PL/Perl functions cannot return type %s",
@@ -2560,8 +2600,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25602600
ObjectIdGetDatum(procStruct->proargtypes.values[i]));
25612601
if (!HeapTupleIsValid(typeTup))
25622602
{
2563-
free(prodesc->proname);
2564-
free(prodesc);
2603+
free_plperl_function(prodesc);
25652604
elog(ERROR,"cache lookup failed for type %u",
25662605
procStruct->proargtypes.values[i]);
25672606
}
@@ -2571,8 +2610,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25712610
if (typeStruct->typtype==TYPTYPE_PSEUDO&&
25722611
procStruct->proargtypes.values[i]!=RECORDOID)
25732612
{
2574-
free(prodesc->proname);
2575-
free(prodesc);
2613+
free_plperl_function(prodesc);
25762614
ereport(ERROR,
25772615
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25782616
errmsg("PL/Perl functions cannot accept type %s",
@@ -2625,8 +2663,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26252663
pfree(proc_source);
26262664
if (!prodesc->reference)/* can this happen? */
26272665
{
2628-
free(prodesc->proname);
2629-
free(prodesc);
2666+
free_plperl_function(prodesc);
26302667
elog(ERROR,"could not create PL/Perl internal procedure");
26312668
}
26322669

@@ -2638,6 +2675,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26382675
proc_ptr=hash_search(plperl_proc_hash,&proc_key,
26392676
HASH_ENTER,NULL);
26402677
proc_ptr->proc_ptr=prodesc;
2678+
increment_prodesc_refcount(prodesc);
26412679
}
26422680

26432681
/* 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