!1797 修复array_set函数数组下界整数回绕问题
Merge pull request !1797 from buter/master
This commit is contained in:
@ -317,6 +317,7 @@ Datum array_cat(PG_FUNCTION_ARGS)
|
||||
|
||||
/* Do this mainly for overflow checking */
|
||||
nitems = ArrayGetNItems(ndims, dims);
|
||||
ArrayCheckBounds(ndims, dims, lbs);
|
||||
|
||||
/* build the result array */
|
||||
ndatabytes = ndatabytes1 + ndatabytes2;
|
||||
|
@ -328,6 +328,8 @@ Datum array_in(PG_FUNCTION_ARGS)
|
||||
|
||||
/* This checks for overflow of the array dimensions */
|
||||
nitems = ArrayGetNItems(ndim, dim);
|
||||
ArrayCheckBounds(ndim, dim, lBound);
|
||||
|
||||
/* Empty array? */
|
||||
if (nitems == 0)
|
||||
PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
|
||||
@ -1224,21 +1226,11 @@ Datum array_recv(PG_FUNCTION_ARGS)
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("array size cannot be negative.")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check overflow of upper bound. (ArrayNItems() below checks that
|
||||
* dim[i] >= 0)
|
||||
*/
|
||||
if (dim[i] != 0) {
|
||||
int ub = lBound[i] + dim[i] - 1;
|
||||
|
||||
if (lBound[i] > ub)
|
||||
ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range")));
|
||||
}
|
||||
}
|
||||
|
||||
/* This checks for overflow of array dimensions */
|
||||
nitems = ArrayGetNItems(ndim, dim);
|
||||
ArrayCheckBounds(ndim, dim, lBound);
|
||||
|
||||
/*
|
||||
* We arrange to look up info about element type, including its receive
|
||||
@ -2944,7 +2936,7 @@ ArrayType* array_set(ArrayType* array, int nSubscripts, const int* indx, Datum d
|
||||
if (nSubscripts != 1)
|
||||
ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts")));
|
||||
|
||||
if (indx[0] < 0 || indx[0] * elmlen >= arraytyplen)
|
||||
if (indx[0] < 0 || elmlen == 0 || indx[0] >= arraytyplen / elmlen)
|
||||
ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array subscript out of range")));
|
||||
|
||||
if (isNull)
|
||||
@ -3034,6 +3026,8 @@ ArrayType* array_set(ArrayType* array, int nSubscripts, const int* indx, Datum d
|
||||
* Compute sizes of items and areas to copy
|
||||
*/
|
||||
newnitems = ArrayGetNItems(ndim, dim);
|
||||
ArrayCheckBounds(ndim, dim, lb);
|
||||
|
||||
if (newhasnulls)
|
||||
overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
|
||||
else
|
||||
@ -3284,6 +3278,7 @@ ArrayType* array_set_slice(ArrayType* array, int nSubscripts, int* upperIndx, in
|
||||
|
||||
/* Do this mainly to check for overflow */
|
||||
nitems = ArrayGetNItems(ndim, dim);
|
||||
ArrayCheckBounds(ndim, dim, lb);
|
||||
|
||||
/*
|
||||
* Make sure source array has enough entries. Note we ignore the shape of
|
||||
@ -3694,6 +3689,7 @@ ArrayType* construct_md_array(Datum* elems, bool* nulls, int ndims, int* dims, c
|
||||
return construct_empty_array(elmtype);
|
||||
|
||||
nelems = ArrayGetNItems(ndims, dims);
|
||||
ArrayCheckBounds(ndims, dims, lbs);
|
||||
|
||||
/* compute required space */
|
||||
nbytes = 0;
|
||||
@ -5455,6 +5451,7 @@ static ArrayType* array_fill_internal(
|
||||
return construct_empty_array(elmtype);
|
||||
|
||||
nitems = ArrayGetNItems(ndims, dimv);
|
||||
ArrayCheckBounds(ndims, dimv, lbsv);
|
||||
|
||||
/*
|
||||
* We arrange to look up info about element type only once per series of
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/int.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/memutils.h"
|
||||
@ -100,6 +101,31 @@ int ArrayGetNItems(int ndim, const int* dims)
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify sanity of proposed lower-bound values for an array
|
||||
*
|
||||
* The lower-bound values must not be so large as to cause overflow when
|
||||
* calculating subscripts, e.g. lower bound 2147483640 with length 10
|
||||
* must be disallowed. We actually insist that dims[i] + lb[i] be
|
||||
* computable without overflow, meaning that an array with last subscript
|
||||
* equal to INT_MAX will be disallowed.
|
||||
*
|
||||
* It is assumed that the caller already called ArrayGetNItems, so that
|
||||
* overflowed (negative) dims[] values have been eliminated.
|
||||
*/
|
||||
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < ndim; i++) {
|
||||
/* PG_USED_FOR_ASSERTS_ONLY prevents variable-isn't-read warnings */
|
||||
int32 sum PG_USED_FOR_ASSERTS_ONLY;
|
||||
|
||||
if (pg_add_s32_overflow(dims[i], lb[i], &sum))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("array lower bound is too large: %d", lb[i])));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute ranges (sub-array dimensions) for an array slice
|
||||
*
|
||||
|
@ -247,6 +247,7 @@ extern int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign,
|
||||
extern int ArrayGetOffset(int n, const int* dim, const int* lb, const int* indx);
|
||||
extern int ArrayGetOffset0(int n, const int* tup, const int* scale);
|
||||
extern int ArrayGetNItems(int ndim, const int* dims);
|
||||
extern void ArrayCheckBounds(int ndim, const int *dims, const int *lb);
|
||||
extern void mda_get_range(int n, int* span, const int* st, const int* endp);
|
||||
extern void mda_get_prod(int n, const int* range, int* prod);
|
||||
extern void mda_get_offset_values(int n, int* dist, const int* prod, const int* span);
|
||||
|
@ -561,25 +561,65 @@ declare
|
||||
end;
|
||||
|
||||
drop table testtbl;
|
||||
select array_cat(
|
||||
array_cat(
|
||||
array_extendnull(
|
||||
array_cat('[2147483645:2147483647]={1,2,3}'::int[], array[4]),
|
||||
1
|
||||
),
|
||||
array_extendnull(
|
||||
array_cat('[2147483645:2147483647]={10,20,30}'::int[], array[40]),
|
||||
1
|
||||
)
|
||||
),
|
||||
array[0,0,0,0,0,0,0,0,0]
|
||||
) as result;
|
||||
|
||||
DECLARE
|
||||
id_arr int[];
|
||||
BEGIN
|
||||
id_arr[2047483630] = 1;
|
||||
id_arr[2147483647] = 1;
|
||||
id_arr[2047483641] = 1;
|
||||
raise notice '%,%',id_arr[2147483644],id_arr[2147483645];
|
||||
END;
|
||||
/
|
||||
ERROR: array lower bound is too large: 2147483645
|
||||
LINE 13: array_cat('[2147483645:2147483647]={1,2,3}'::int...
|
||||
^
|
||||
CONTEXT: referenced column: result
|
||||
drop table if exists cve_2021_32027_tb;
|
||||
NOTICE: table "cve_2021_32027_tb" does not exist, skipping
|
||||
create table cve_2021_32027_tb (i int, p point);
|
||||
insert into cve_2021_32027_tb(p) values('(1,1)');
|
||||
update cve_2021_32027_tb set p[2147483647] = 0 returning *;
|
||||
ERROR: array subscript out of range
|
||||
CONTEXT: referenced column: p
|
||||
update cve_2021_32027_tb set p[268435456] = 0 returning *;
|
||||
ERROR: array subscript out of range
|
||||
CONTEXT: referenced column: p
|
||||
update cve_2021_32027_tb set p[536870912] = 0 returning *;
|
||||
ERROR: array subscript out of range
|
||||
CONTEXT: referenced column: p
|
||||
--------------------------------------------------
|
||||
------------------ END OF TESTS ------------------
|
||||
--------------------------------------------------
|
||||
|
||||
drop table if exists cve_2021_32027_tb;
|
||||
drop package if exists pckg_test;
|
||||
NOTICE: drop cascades to function plpgsql_array.proc_test()
|
||||
drop procedure if exists pro1;
|
||||
drop function if exists functype;
|
||||
NOTICE: function functype() does not exist, skipping
|
||||
drop function if exists myfunc;
|
||||
drop function if exists myarray_sort;
|
||||
drop table if exists tmp;
|
||||
drop table if exists customers;
|
||||
drop type if exists functype;
|
||||
NOTICE: type "functype" does not exist, skipping
|
||||
drop type if exists mytype2;
|
||||
drop type if exists mytype;
|
||||
|
||||
-- clean up --
|
||||
drop schema if exists plpgsql_array cascade;
|
||||
NOTICE: drop cascades to function plpgsql_array.proc_test()
|
||||
NOTICE: function functype() does not exist, skipping
|
||||
NOTICE: type "functype" does not exist, skipping
|
||||
NOTICE: drop cascades to function name_list(integer)
|
||||
NOTICE: drop cascades to 2 other objects
|
||||
DETAIL: drop cascades to function name_list(integer)
|
||||
drop cascades to table testtbl
|
||||
|
@ -451,11 +451,41 @@ declare
|
||||
end;
|
||||
|
||||
drop table testtbl;
|
||||
select array_cat(
|
||||
array_cat(
|
||||
array_extendnull(
|
||||
array_cat('[2147483645:2147483647]={1,2,3}'::int[], array[4]),
|
||||
1
|
||||
),
|
||||
array_extendnull(
|
||||
array_cat('[2147483645:2147483647]={10,20,30}'::int[], array[40]),
|
||||
1
|
||||
)
|
||||
),
|
||||
array[0,0,0,0,0,0,0,0,0]
|
||||
) as result;
|
||||
|
||||
DECLARE
|
||||
id_arr int[];
|
||||
BEGIN
|
||||
id_arr[2047483630] = 1;
|
||||
id_arr[2147483647] = 1;
|
||||
id_arr[2047483641] = 1;
|
||||
raise notice '%,%',id_arr[2147483644],id_arr[2147483645];
|
||||
END;
|
||||
/
|
||||
|
||||
drop table if exists cve_2021_32027_tb;
|
||||
create table cve_2021_32027_tb (i int, p point);
|
||||
insert into cve_2021_32027_tb(p) values('(1,1)');
|
||||
update cve_2021_32027_tb set p[2147483647] = 0 returning *;
|
||||
update cve_2021_32027_tb set p[268435456] = 0 returning *;
|
||||
update cve_2021_32027_tb set p[536870912] = 0 returning *;
|
||||
|
||||
--------------------------------------------------
|
||||
------------------ END OF TESTS ------------------
|
||||
--------------------------------------------------
|
||||
|
||||
drop table if exists cve_2021_32027_tb;
|
||||
drop package if exists pckg_test;
|
||||
drop procedure if exists pro1;
|
||||
drop function if exists functype;
|
||||
|
Reference in New Issue
Block a user