!1797 修复array_set函数数组下界整数回绕问题

Merge pull request !1797 from buter/master
This commit is contained in:
opengauss-bot
2022-06-11 06:12:39 +00:00
committed by Gitee
6 changed files with 115 additions and 20 deletions

View File

@ -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;

View File

@ -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

View File

@ -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
*

View File

@ -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);

View File

@ -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

View File

@ -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;