mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Make plperl's handling of Perl arrays safer and more consistent.
plperl_func_handler()'s stanza for handling an arrayref result in a SETOF function could loop forever (or at least till OOM) when given a tied array, since av_fetch won't necessarily ever return a null pointer in that case. Be consistent with the other places where we traverse a perl array: call av_len() once and use len+1 as the loop limit, silently ignoring any null pointers we get back from that range of subscripts. But actually, Perl's preferred locution for this seems to be to use av_count() not av_len()+1. av_count() seems better since there's less risk of forgetting to add 1. Also, both of those functions return Size_t (or SSize_t) not int, creating at least a theoretical overflow hazard. While we're modernizing this, let's use the correct variable type where we can, and include an overflow check where we can't. Reported-by: Claude Code (via Noah Misch) Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com> Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us Backpatch-through: 14
This commit is contained in:
@@ -135,12 +135,11 @@ static JsonbValue *
|
||||
AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
|
||||
{
|
||||
dTHX;
|
||||
SSize_t pcount = av_len(in) + 1;
|
||||
SSize_t i;
|
||||
Size_t pcount = av_count(in);
|
||||
|
||||
pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
|
||||
|
||||
for (i = 0; i < pcount; i++)
|
||||
for (Size_t i = 0; i < pcount; i++)
|
||||
{
|
||||
SV **value = av_fetch(in, i, FALSE);
|
||||
|
||||
|
||||
@@ -278,6 +278,7 @@ static void array_to_datum_internal(AV *av, ArrayBuildState **astatep,
|
||||
int *ndims, int *dims, int cur_depth,
|
||||
Oid elemtypid, int32 typmod,
|
||||
FmgrInfo *finfo, Oid typioparam);
|
||||
static int av_count_limit(AV *av);
|
||||
static Datum plperl_hash_to_datum(SV *src, TupleDesc td);
|
||||
|
||||
static void plperl_init_shared_libs(pTHX);
|
||||
@@ -1169,8 +1170,8 @@ get_perl_array_ref(SV *sv)
|
||||
* is frozen).
|
||||
*
|
||||
* Caller is required to have set dims[cur_depth - 1] to the length of the
|
||||
* input array, i.e., av_len(av) + 1. We make this requirement so as to
|
||||
* avoid reading av_len() twice, which is hazardous for tied arrays.
|
||||
* input array, i.e., av_count_limit(av). We make this requirement so as to
|
||||
* avoid reading av_count() twice, which is hazardous for tied arrays.
|
||||
*/
|
||||
static void
|
||||
array_to_datum_internal(AV *av, ArrayBuildState **astatep,
|
||||
@@ -1210,11 +1211,11 @@ array_to_datum_internal(AV *av, ArrayBuildState **astatep,
|
||||
errmsg("number of array dimensions exceeds the maximum allowed (%d)",
|
||||
MAXDIM)));
|
||||
/* OK, add a dimension */
|
||||
dims[*ndims] = av_len(nav) + 1;
|
||||
dims[*ndims] = av_count_limit(nav);
|
||||
(*ndims)++;
|
||||
}
|
||||
else if (cur_depth >= *ndims ||
|
||||
av_len(nav) + 1 != dims[cur_depth])
|
||||
av_count_limit(nav) != dims[cur_depth])
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("multidimensional arrays must have array expressions with matching dimensions")));
|
||||
@@ -1256,6 +1257,25 @@ array_to_datum_internal(AV *av, ArrayBuildState **astatep,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* av_count returns Size_t, so at least in theory it could overrun INT_MAX.
|
||||
* As long as we have to check, let's throw error for anything above
|
||||
* MaxArraySize, which will surely fail later.
|
||||
*/
|
||||
static int
|
||||
av_count_limit(AV *av)
|
||||
{
|
||||
dTHX;
|
||||
Size_t cnt = av_count(av);
|
||||
|
||||
if (cnt > MaxArraySize)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("array size exceeds the maximum allowed (%zu)",
|
||||
MaxArraySize)));
|
||||
return (int) cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert perl array ref to a datum
|
||||
*/
|
||||
@@ -1283,7 +1303,7 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
|
||||
_sv_to_datum_finfo(elemtypid, &finfo, &typioparam);
|
||||
|
||||
memset(dims, 0, sizeof(dims));
|
||||
dims[0] = av_len(nav) + 1;
|
||||
dims[0] = av_count_limit(nav);
|
||||
|
||||
array_to_datum_internal(nav, &astate,
|
||||
&ndims, dims, 1,
|
||||
@@ -2472,14 +2492,15 @@ plperl_func_handler(PG_FUNCTION_ARGS)
|
||||
if (sav)
|
||||
{
|
||||
dTHX;
|
||||
int i = 0;
|
||||
SV **svp = 0;
|
||||
AV *rav = (AV *) SvRV(sav);
|
||||
Size_t alen = av_count(rav);
|
||||
|
||||
while ((svp = av_fetch(rav, i, FALSE)) != NULL)
|
||||
for (Size_t i = 0; i < alen; i++)
|
||||
{
|
||||
plperl_return_next_internal(*svp);
|
||||
i++;
|
||||
SV **svp = av_fetch(rav, i, FALSE);
|
||||
|
||||
if (svp)
|
||||
plperl_return_next_internal(*svp);
|
||||
}
|
||||
}
|
||||
else if (SvOK(perlret))
|
||||
|
||||
Reference in New Issue
Block a user