Skip to content

Commit 11213d4

Browse files
committed
Fix oversights in array manipulation.
The nested-arrays code path in ExecEvalArrayExpr() used palloc to allocate the result array, whereas every other array-creating function has used palloc0 since 18c0b4e. This mostly works, but unused bits past the end of the nulls bitmap may end up undefined. That causes valgrind complaints with -DWRITE_READ_PARSE_PLAN_TREES, and could cause planner misbehavior as cited in 18c0b4e. There seems no very good reason why we should strive to avoid palloc0 in just this one case, so fix it the easy way with s/palloc/palloc0/. While looking at that I noted that we also failed to check for overflow of "nbytes" and "nitems" while summing the sizes of the sub-arrays, potentially allowing a crash due to undersized output allocation. For "nbytes", follow the policy used by other array-munging code of checking for overflow after each addition. (As elsewhere, the last addition of the array's overhead space doesn't need an extra check, since palloc itself will catch a value between 1Gb and 2Gb.) For "nitems", there's no very good reason to sum the inputs at all, since we can perfectly well use ArrayGetNItems' result instead of ignoring it. Per discussion of this bug, also remove redundant zeroing of the nulls bitmap in array_set_element and array_set_slice. Patch by Alexander Lakhin and myself, per bug #17858 from Alexander Lakhin; thanks also to Richard Guo. These bugs are a dozen years old, so back-patch to all supported branches. Discussion: https://postgr.es/m/17858-8fd287fd3663d051@postgresql.org
1 parent 8fd5aa7 commit 11213d4

File tree

2 files changed

+11
-8
lines changed

2 files changed

+11
-8
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,7 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
27062706
{
27072707
/* Must be nested array expressions */
27082708
int nbytes = 0;
2709-
int nitems = 0;
2709+
int nitems;
27102710
int outer_nelems = 0;
27112711
int elem_ndims = 0;
27122712
int *elem_dims = NULL;
@@ -2801,9 +2801,14 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
28012801
subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
28022802
subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
28032803
nbytes += subbytes[outer_nelems];
2804+
/* check for overflow of total request */
2805+
if (!AllocSizeIsValid(nbytes))
2806+
ereport(ERROR,
2807+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2808+
errmsg("array size exceeds the maximum allowed (%d)",
2809+
(int) MaxAllocSize)));
28042810
subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
28052811
ARR_DIMS(array));
2806-
nitems += subnitems[outer_nelems];
28072812
havenulls |= ARR_HASNULL(array);
28082813
outer_nelems++;
28092814
}
@@ -2837,7 +2842,7 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
28372842
}
28382843

28392844
/* check for subscript overflow */
2840-
(void) ArrayGetNItems(ndims, dims);
2845+
nitems = ArrayGetNItems(ndims, dims);
28412846
ArrayCheckBounds(ndims, dims, lbs);
28422847

28432848
if (havenulls)
@@ -2851,7 +2856,7 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
28512856
nbytes += ARR_OVERHEAD_NONULLS(ndims);
28522857
}
28532858

2854-
result = (ArrayType *) palloc(nbytes);
2859+
result = (ArrayType *) palloc0(nbytes);
28552860
SET_VARSIZE(result, nbytes);
28562861
result->ndim = ndims;
28572862
result->dataoffset = dataoffset;

src/backend/utils/adt/arrayfuncs.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,8 +2459,7 @@ array_set_element(Datum arraydatum,
24592459
{
24602460
bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
24612461

2462-
/* Zero the bitmap to take care of marking inserted positions null */
2463-
MemSet(newnullbitmap, 0, (newnitems + 7) / 8);
2462+
/* palloc0 above already marked any inserted positions as nulls */
24642463
/* Fix the inserted value */
24652464
if (addedafter)
24662465
array_set_isnull(newnullbitmap, newnitems - 1, isNull);
@@ -3076,8 +3075,7 @@ array_set_slice(Datum arraydatum,
30763075
bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
30773076
bits8 *oldnullbitmap = ARR_NULLBITMAP(array);
30783077

3079-
/* Zero the bitmap to handle marking inserted positions null */
3080-
MemSet(newnullbitmap, 0, (nitems + 7) / 8);
3078+
/* palloc0 above already marked any inserted positions as nulls */
30813079
array_bitmap_copy(newnullbitmap, addedbefore,
30823080
oldnullbitmap, 0,
30833081
itemsbefore);

0 commit comments

Comments
 (0)