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

Commit0952811

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 parent25b6df1 commit0952811

File tree

3 files changed

+98
-33
lines changed

3 files changed

+98
-33
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,21 @@ CONTEXT: PL/Perl anonymous code block
597597
DO $do$ use warnings FATAL => qw(void) ; my @y; my $x = sort @y; 1; $do$ LANGUAGE plperl;
598598
ERROR: Useless use of sort in scalar context at line 1.
599599
CONTEXT: PL/Perl anonymous code block
600+
-- check safe behavior when a function body is replaced during execution
601+
CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS $$
602+
spi_exec_query('CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS \'return $_[0] * 3;\' LANGUAGE plperl;');
603+
spi_exec_query('select self_modify(42) AS a');
604+
return $_[0] * 2;
605+
$$ LANGUAGE plperl;
606+
SELECT self_modify(42);
607+
self_modify
608+
-------------
609+
84
610+
(1 row)
611+
612+
SELECT self_modify(42);
613+
self_modify
614+
-------------
615+
126
616+
(1 row)
617+

‎src/pl/plperl/plperl.c

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ PG_MODULE_MAGIC;
6767
*
6868
* The plperl_interp_desc structs are kept in a Postgres hash table indexed
6969
* by userid OID, with OID 0 used for the single untrusted interpreter.
70+
* Once created, an interpreter is kept for the life of the process.
7071
*
7172
* We start out by creating a "held" interpreter, which we initialize
7273
* only as far as we can do without deciding if it will be trusted or
@@ -92,27 +93,43 @@ typedef struct plperl_interp_desc
9293

9394
/**********************************************************************
9495
* The information we cache about loaded procedures
96+
*
97+
* The refcount field counts the struct's reference from the hash table shown
98+
* below, plus one reference for each function call level that is using the
99+
* struct. We can release the struct, and the associated Perl sub, when the
100+
* refcount goes to zero.
95101
**********************************************************************/
96102
typedefstructplperl_proc_desc
97103
{
98104
char*proname;/* user name of procedure */
99-
TransactionIdfn_xmin;
105+
TransactionIdfn_xmin;/* xmin/TID of procedure's pg_proc tuple */
100106
ItemPointerDatafn_tid;
107+
intrefcount;/* reference count of this struct */
108+
SV*reference;/* CODE reference for Perl sub */
101109
plperl_interp_desc*interp;/* interpreter it's created in */
102-
boolfn_readonly;
103-
boollanpltrusted;
110+
boolfn_readonly;/* is function readonly (not volatile)? */
111+
boollanpltrusted;/* is it plperl, rather than plperlu? */
104112
boolfn_retistuple;/* true, if function returns tuple */
105113
boolfn_retisset;/* true, if function returns set */
106114
boolfn_retisarray;/* true if function returns array */
115+
/* Conversion info for function's result type: */
107116
Oidresult_oid;/* Oid of result type */
108117
FmgrInforesult_in_func;/* I/O function and arg for result type */
109118
Oidresult_typioparam;
119+
/* Conversion info for function's argument types: */
110120
intnargs;
111121
FmgrInfoarg_out_func[FUNC_MAX_ARGS];
112122
boolarg_is_rowtype[FUNC_MAX_ARGS];
113-
SV*reference;
114123
}plperl_proc_desc;
115124

125+
#defineincrement_prodesc_refcount(prodesc) \
126+
((prodesc)->refcount++)
127+
#definedecrement_prodesc_refcount(prodesc) \
128+
do { \
129+
if (--((prodesc)->refcount) <= 0) \
130+
free_plperl_function(prodesc); \
131+
} while(0)
132+
116133
/**********************************************************************
117134
* For speedy lookup, we maintain a hash table mapping from
118135
* function OID + trigger flag + user OID to plperl_proc_desc pointers.
@@ -217,6 +234,8 @@ static void set_interp_require(bool trusted);
217234
staticDatumplperl_func_handler(PG_FUNCTION_ARGS);
218235
staticDatumplperl_trigger_handler(PG_FUNCTION_ARGS);
219236

237+
staticvoidfree_plperl_function(plperl_proc_desc*prodesc);
238+
220239
staticplperl_proc_desc*compile_plperl_function(Oidfn_oid,boolis_trigger);
221240

222241
staticSV*plperl_hash_from_tuple(HeapTupletuple,TupleDesctupdesc);
@@ -1228,19 +1247,24 @@ plperl_call_handler(PG_FUNCTION_ARGS)
12281247

12291248
PG_TRY();
12301249
{
1250+
current_call_data=NULL;
12311251
if (CALLED_AS_TRIGGER(fcinfo))
12321252
retval=PointerGetDatum(plperl_trigger_handler(fcinfo));
12331253
else
12341254
retval=plperl_func_handler(fcinfo);
12351255
}
12361256
PG_CATCH();
12371257
{
1258+
if (current_call_data&&current_call_data->prodesc)
1259+
decrement_prodesc_refcount(current_call_data->prodesc);
12381260
current_call_data=save_call_data;
12391261
activate_interpreter(oldinterp);
12401262
PG_RE_THROW();
12411263
}
12421264
PG_END_TRY();
12431265

1266+
if (current_call_data&&current_call_data->prodesc)
1267+
decrement_prodesc_refcount(current_call_data->prodesc);
12441268
current_call_data=save_call_data;
12451269
activate_interpreter(oldinterp);
12461270
returnretval;
@@ -1292,14 +1316,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
12921316
desc.nargs=0;
12931317
desc.reference=NULL;
12941318

1295-
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1296-
current_call_data->fcinfo=&fake_fcinfo;
1297-
current_call_data->prodesc=&desc;
1298-
12991319
PG_TRY();
13001320
{
13011321
SV*perlret;
13021322

1323+
current_call_data= (plperl_call_data*)palloc0(sizeof(plperl_call_data));
1324+
current_call_data->fcinfo=&fake_fcinfo;
1325+
current_call_data->prodesc=&desc;
1326+
/* we do not bother with refcounting the fake prodesc */
1327+
13031328
if (SPI_connect()!=SPI_OK_CONNECT)
13041329
elog(ERROR,"could not connect to SPI manager");
13051330

@@ -1659,6 +1684,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
16591684

16601685
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, false);
16611686
current_call_data->prodesc=prodesc;
1687+
increment_prodesc_refcount(prodesc);
16621688

16631689
/* Set a callback for error reporting */
16641690
pl_error_context.callback=plperl_exec_callback;
@@ -1820,6 +1846,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
18201846
/* Find or compile the function */
18211847
prodesc=compile_plperl_function(fcinfo->flinfo->fn_oid, true);
18221848
current_call_data->prodesc=prodesc;
1849+
increment_prodesc_refcount(prodesc);
18231850

18241851
/* Set a callback for error reporting */
18251852
pl_error_context.callback=plperl_exec_callback;
@@ -1928,23 +1955,35 @@ validate_plperl_function(plperl_proc_ptr *proc_ptr, HeapTuple procTup)
19281955

19291956
/* Otherwise, unlink the obsoleted entry from the hashtable ... */
19301957
proc_ptr->proc_ptr=NULL;
1931-
/* ... and throw it away */
1932-
if (prodesc->reference)
1933-
{
1934-
plperl_interp_desc*oldinterp=plperl_active_interp;
1935-
1936-
activate_interpreter(prodesc->interp);
1937-
SvREFCNT_dec(prodesc->reference);
1938-
activate_interpreter(oldinterp);
1939-
}
1940-
free(prodesc->proname);
1941-
free(prodesc);
1958+
/* ... and release the corresponding refcount, probably deleting it */
1959+
decrement_prodesc_refcount(prodesc);
19421960
}
19431961

19441962
return false;
19451963
}
19461964

19471965

1966+
staticvoid
1967+
free_plperl_function(plperl_proc_desc*prodesc)
1968+
{
1969+
Assert(prodesc->refcount <=0);
1970+
/* Release CODE reference, if we have one, from the appropriate interp */
1971+
if (prodesc->reference)
1972+
{
1973+
plperl_interp_desc*oldinterp=plperl_active_interp;
1974+
1975+
activate_interpreter(prodesc->interp);
1976+
SvREFCNT_dec(prodesc->reference);
1977+
activate_interpreter(oldinterp);
1978+
}
1979+
/* Get rid of what we conveniently can of our own structs */
1980+
/* (FmgrInfo subsidiary info will get leaked ...) */
1981+
if (prodesc->proname)
1982+
free(prodesc->proname);
1983+
free(prodesc);
1984+
}
1985+
1986+
19481987
staticplperl_proc_desc*
19491988
compile_plperl_function(Oidfn_oid,boolis_trigger)
19501989
{
@@ -2015,12 +2054,17 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
20152054
ereport(ERROR,
20162055
(errcode(ERRCODE_OUT_OF_MEMORY),
20172056
errmsg("out of memory")));
2057+
/* Initialize all fields to 0 so free_plperl_function is safe */
20182058
MemSet(prodesc,0,sizeof(plperl_proc_desc));
2059+
20192060
prodesc->proname=strdup(NameStr(procStruct->proname));
20202061
if (prodesc->proname==NULL)
2062+
{
2063+
free_plperl_function(prodesc);
20212064
ereport(ERROR,
20222065
(errcode(ERRCODE_OUT_OF_MEMORY),
20232066
errmsg("out of memory")));
2067+
}
20242068
prodesc->fn_xmin=HeapTupleHeaderGetXmin(procTup->t_data);
20252069
prodesc->fn_tid=procTup->t_self;
20262070

@@ -2035,8 +2079,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
20352079
ObjectIdGetDatum(procStruct->prolang));
20362080
if (!HeapTupleIsValid(langTup))
20372081
{
2038-
free(prodesc->proname);
2039-
free(prodesc);
2082+
free_plperl_function(prodesc);
20402083
elog(ERROR,"cache lookup failed for language %u",
20412084
procStruct->prolang);
20422085
}
@@ -2055,8 +2098,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
20552098
ObjectIdGetDatum(procStruct->prorettype));
20562099
if (!HeapTupleIsValid(typeTup))
20572100
{
2058-
free(prodesc->proname);
2059-
free(prodesc);
2101+
free_plperl_function(prodesc);
20602102
elog(ERROR,"cache lookup failed for type %u",
20612103
procStruct->prorettype);
20622104
}
@@ -2070,17 +2112,15 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
20702112
/* okay */ ;
20712113
elseif (procStruct->prorettype==TRIGGEROID)
20722114
{
2073-
free(prodesc->proname);
2074-
free(prodesc);
2115+
free_plperl_function(prodesc);
20752116
ereport(ERROR,
20762117
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20772118
errmsg("trigger functions can only be called "
20782119
"as triggers")));
20792120
}
20802121
else
20812122
{
2082-
free(prodesc->proname);
2083-
free(prodesc);
2123+
free_plperl_function(prodesc);
20842124
ereport(ERROR,
20852125
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
20862126
errmsg("PL/Perl functions cannot return type %s",
@@ -2115,8 +2155,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
21152155
ObjectIdGetDatum(procStruct->proargtypes.values[i]));
21162156
if (!HeapTupleIsValid(typeTup))
21172157
{
2118-
free(prodesc->proname);
2119-
free(prodesc);
2158+
free_plperl_function(prodesc);
21202159
elog(ERROR,"cache lookup failed for type %u",
21212160
procStruct->proargtypes.values[i]);
21222161
}
@@ -2125,8 +2164,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
21252164
/* Disallow pseudotype argument */
21262165
if (typeStruct->typtype==TYPTYPE_PSEUDO)
21272166
{
2128-
free(prodesc->proname);
2129-
free(prodesc);
2167+
free_plperl_function(prodesc);
21302168
ereport(ERROR,
21312169
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
21322170
errmsg("PL/Perl functions cannot accept type %s",
@@ -2172,8 +2210,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
21722210
pfree(proc_source);
21732211
if (!prodesc->reference)/* can this happen? */
21742212
{
2175-
free(prodesc->proname);
2176-
free(prodesc);
2213+
free_plperl_function(prodesc);
21772214
elog(ERROR,"could not create PL/Perl internal procedure");
21782215
}
21792216

@@ -2185,6 +2222,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
21852222
proc_ptr=hash_search(plperl_proc_hash,&proc_key,
21862223
HASH_ENTER,NULL);
21872224
proc_ptr->proc_ptr=prodesc;
2225+
increment_prodesc_refcount(prodesc);
21882226
}
21892227

21902228
/* restore previous error callback */

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,12 @@ DO $do$ use strict; my $name = "foo"; my $ref = $$name; $do$ LANGUAGE plperl;
391391
-- yields "ERROR: Useless use of sort in scalar context."
392392
DO $do$ use warnings FATAL=> qw(void) ; my @y; my $x= sort @y;1; $do$ LANGUAGE plperl;
393393

394+
-- check safe behavior when a function body is replaced during execution
395+
CREATE OR REPLACEFUNCTIONself_modify(INTEGER) RETURNSINTEGERAS $$
396+
spi_exec_query('CREATE OR REPLACE FUNCTION self_modify(INTEGER) RETURNS INTEGER AS\'return $_[0] * 3;\' LANGUAGE plperl;');
397+
spi_exec_query('select self_modify(42) AS a');
398+
return $_[0]*2;
399+
$$ LANGUAGE plperl;
400+
401+
SELECT self_modify(42);
402+
SELECT self_modify(42);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp