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

Commit81ead89

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 parentaf3de2d commit81ead89

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

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

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

257+
staticvoidfree_plperl_function(plperl_proc_desc*prodesc);
258+
240259
staticplperl_proc_desc*compile_plperl_function(Oidfn_oid,boolis_trigger);
241260

242261
staticSV*plperl_hash_from_tuple(HeapTupletuple,TupleDesctupdesc);
@@ -1680,19 +1699,24 @@ plperl_call_handler(PG_FUNCTION_ARGS)
16801699

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

1718+
if (current_call_data&&current_call_data->prodesc)
1719+
decrement_prodesc_refcount(current_call_data->prodesc);
16961720
current_call_data=save_call_data;
16971721
activate_interpreter(oldinterp);
16981722
returnretval;
@@ -1744,14 +1768,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
17441768
desc.nargs=0;
17451769
desc.reference=NULL;
17461770

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

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

@@ -2145,6 +2170,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
21452170

21462171
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, false);
21472172
current_call_data->prodesc=prodesc;
2173+
increment_prodesc_refcount(prodesc);
21482174

21492175
/* Set a callback for error reporting */
21502176
pl_error_context.callback=plperl_exec_callback;
@@ -2265,6 +2291,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
22652291
/* Find or compile the function */
22662292
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, true);
22672293
current_call_data->prodesc=prodesc;
2294+
increment_prodesc_refcount(prodesc);
22682295

22692296
/* Set a callback for error reporting */
22702297
pl_error_context.callback=plperl_exec_callback;
@@ -2374,23 +2401,35 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
23742401

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

23902408
return false;
23912409
}
23922410

23932411

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

@@ -2481,8 +2525,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
24812525
ObjectIdGetDatum(procStruct->prolang));
24822526
if (!HeapTupleIsValid(langTup))
24832527
{
2484-
free(prodesc->proname);
2485-
free(prodesc);
2528+
free_plperl_function(prodesc);
24862529
elog(ERROR,"cache lookup failed for language %u",
24872530
procStruct->prolang);
24882531
}
@@ -2501,8 +2544,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25012544
ObjectIdGetDatum(procStruct->prorettype));
25022545
if (!HeapTupleIsValid(typeTup))
25032546
{
2504-
free(prodesc->proname);
2505-
free(prodesc);
2547+
free_plperl_function(prodesc);
25062548
elog(ERROR,"cache lookup failed for type %u",
25072549
procStruct->prorettype);
25082550
}
@@ -2516,17 +2558,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25162558
/* okay */ ;
25172559
elseif (procStruct->prorettype==TRIGGEROID)
25182560
{
2519-
free(prodesc->proname);
2520-
free(prodesc);
2561+
free_plperl_function(prodesc);
25212562
ereport(ERROR,
25222563
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25232564
errmsg("trigger functions can only be called "
25242565
"as triggers")));
25252566
}
25262567
else
25272568
{
2528-
free(prodesc->proname);
2529-
free(prodesc);
2569+
free_plperl_function(prodesc);
25302570
ereport(ERROR,
25312571
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25322572
errmsg("PL/Perl functions cannot return type %s",
@@ -2561,8 +2601,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25612601
ObjectIdGetDatum(procStruct->proargtypes.values[i]));
25622602
if (!HeapTupleIsValid(typeTup))
25632603
{
2564-
free(prodesc->proname);
2565-
free(prodesc);
2604+
free_plperl_function(prodesc);
25662605
elog(ERROR,"cache lookup failed for type %u",
25672606
procStruct->proargtypes.values[i]);
25682607
}
@@ -2572,8 +2611,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
25722611
if (typeStruct->typtype==TYPTYPE_PSEUDO&&
25732612
procStruct->proargtypes.values[i]!=RECORDOID)
25742613
{
2575-
free(prodesc->proname);
2576-
free(prodesc);
2614+
free_plperl_function(prodesc);
25772615
ereport(ERROR,
25782616
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
25792617
errmsg("PL/Perl functions cannot accept type %s",
@@ -2626,8 +2664,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26262664
pfree(proc_source);
26272665
if (!prodesc->reference)/* can this happen? */
26282666
{
2629-
free(prodesc->proname);
2630-
free(prodesc);
2667+
free_plperl_function(prodesc);
26312668
elog(ERROR,"could not create PL/Perl internal procedure");
26322669
}
26332670

@@ -2639,6 +2676,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
26392676
proc_ptr=hash_search(plperl_proc_hash,&proc_key,
26402677
HASH_ENTER,NULL);
26412678
proc_ptr->proc_ptr=prodesc;
2679+
increment_prodesc_refcount(prodesc);
26422680
}
26432681

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