!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 */
|
/* Do this mainly for overflow checking */
|
||||||
nitems = ArrayGetNItems(ndims, dims);
|
nitems = ArrayGetNItems(ndims, dims);
|
||||||
|
ArrayCheckBounds(ndims, dims, lbs);
|
||||||
|
|
||||||
/* build the result array */
|
/* build the result array */
|
||||||
ndatabytes = ndatabytes1 + ndatabytes2;
|
ndatabytes = ndatabytes1 + ndatabytes2;
|
||||||
|
@ -328,6 +328,8 @@ Datum array_in(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* This checks for overflow of the array dimensions */
|
/* This checks for overflow of the array dimensions */
|
||||||
nitems = ArrayGetNItems(ndim, dim);
|
nitems = ArrayGetNItems(ndim, dim);
|
||||||
|
ArrayCheckBounds(ndim, dim, lBound);
|
||||||
|
|
||||||
/* Empty array? */
|
/* Empty array? */
|
||||||
if (nitems == 0)
|
if (nitems == 0)
|
||||||
PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
|
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),
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||||
errmsg("array size cannot be negative.")));
|
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 */
|
/* This checks for overflow of array dimensions */
|
||||||
nitems = ArrayGetNItems(ndim, dim);
|
nitems = ArrayGetNItems(ndim, dim);
|
||||||
|
ArrayCheckBounds(ndim, dim, lBound);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We arrange to look up info about element type, including its receive
|
* 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)
|
if (nSubscripts != 1)
|
||||||
ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts")));
|
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")));
|
ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("array subscript out of range")));
|
||||||
|
|
||||||
if (isNull)
|
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
|
* Compute sizes of items and areas to copy
|
||||||
*/
|
*/
|
||||||
newnitems = ArrayGetNItems(ndim, dim);
|
newnitems = ArrayGetNItems(ndim, dim);
|
||||||
|
ArrayCheckBounds(ndim, dim, lb);
|
||||||
|
|
||||||
if (newhasnulls)
|
if (newhasnulls)
|
||||||
overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
|
overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
|
||||||
else
|
else
|
||||||
@ -3284,6 +3278,7 @@ ArrayType* array_set_slice(ArrayType* array, int nSubscripts, int* upperIndx, in
|
|||||||
|
|
||||||
/* Do this mainly to check for overflow */
|
/* Do this mainly to check for overflow */
|
||||||
nitems = ArrayGetNItems(ndim, dim);
|
nitems = ArrayGetNItems(ndim, dim);
|
||||||
|
ArrayCheckBounds(ndim, dim, lb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure source array has enough entries. Note we ignore the shape of
|
* 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);
|
return construct_empty_array(elmtype);
|
||||||
|
|
||||||
nelems = ArrayGetNItems(ndims, dims);
|
nelems = ArrayGetNItems(ndims, dims);
|
||||||
|
ArrayCheckBounds(ndims, dims, lbs);
|
||||||
|
|
||||||
/* compute required space */
|
/* compute required space */
|
||||||
nbytes = 0;
|
nbytes = 0;
|
||||||
@ -5455,6 +5451,7 @@ static ArrayType* array_fill_internal(
|
|||||||
return construct_empty_array(elmtype);
|
return construct_empty_array(elmtype);
|
||||||
|
|
||||||
nitems = ArrayGetNItems(ndims, dimv);
|
nitems = ArrayGetNItems(ndims, dimv);
|
||||||
|
ArrayCheckBounds(ndims, dimv, lbsv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We arrange to look up info about element type only once per series of
|
* We arrange to look up info about element type only once per series of
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "knl/knl_variable.h"
|
#include "knl/knl_variable.h"
|
||||||
|
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "common/int.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
@ -100,6 +101,31 @@ int ArrayGetNItems(int ndim, const int* dims)
|
|||||||
return (int)ret;
|
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
|
* 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 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 ArrayGetOffset0(int n, const int* tup, const int* scale);
|
||||||
extern int ArrayGetNItems(int ndim, const int* dims);
|
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_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_prod(int n, const int* range, int* prod);
|
||||||
extern void mda_get_offset_values(int n, int* dist, const int* prod, const int* span);
|
extern void mda_get_offset_values(int n, int* dist, const int* prod, const int* span);
|
||||||
|
@ -561,25 +561,65 @@ declare
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
drop table testtbl;
|
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 ------------------
|
------------------ END OF TESTS ------------------
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
drop table if exists cve_2021_32027_tb;
|
||||||
drop package if exists pckg_test;
|
drop package if exists pckg_test;
|
||||||
|
NOTICE: drop cascades to function plpgsql_array.proc_test()
|
||||||
drop procedure if exists pro1;
|
drop procedure if exists pro1;
|
||||||
drop function if exists functype;
|
drop function if exists functype;
|
||||||
|
NOTICE: function functype() does not exist, skipping
|
||||||
drop function if exists myfunc;
|
drop function if exists myfunc;
|
||||||
drop function if exists myarray_sort;
|
drop function if exists myarray_sort;
|
||||||
drop table if exists tmp;
|
drop table if exists tmp;
|
||||||
drop table if exists customers;
|
drop table if exists customers;
|
||||||
drop type if exists functype;
|
drop type if exists functype;
|
||||||
|
NOTICE: type "functype" does not exist, skipping
|
||||||
drop type if exists mytype2;
|
drop type if exists mytype2;
|
||||||
drop type if exists mytype;
|
drop type if exists mytype;
|
||||||
|
|
||||||
-- clean up --
|
-- clean up --
|
||||||
drop schema if exists plpgsql_array cascade;
|
drop schema if exists plpgsql_array cascade;
|
||||||
NOTICE: drop cascades to function plpgsql_array.proc_test()
|
NOTICE: drop cascades to 2 other objects
|
||||||
NOTICE: function functype() does not exist, skipping
|
DETAIL: drop cascades to function name_list(integer)
|
||||||
NOTICE: type "functype" does not exist, skipping
|
drop cascades to table testtbl
|
||||||
NOTICE: drop cascades to function name_list(integer)
|
|
||||||
|
@ -451,11 +451,41 @@ declare
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
drop table testtbl;
|
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 ------------------
|
------------------ END OF TESTS ------------------
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
drop table if exists cve_2021_32027_tb;
|
||||||
drop package if exists pckg_test;
|
drop package if exists pckg_test;
|
||||||
drop procedure if exists pro1;
|
drop procedure if exists pro1;
|
||||||
drop function if exists functype;
|
drop function if exists functype;
|
||||||
|
Reference in New Issue
Block a user