aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-01-17 12:38:52 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2011-01-17 12:41:01 -0500
commit2a0abe10f3899d5b802f9df6a7ceffc72f513f16 (patch)
treee6df2af5bc5ccd6ca61eb7eb5b4ac761b378548f /src
parentebbf741d5d449f6fdc1983aca54d1f232d866b16 (diff)
downloadpostgresql-2a0abe10f3899d5b802f9df6a7ceffc72f513f16.tar.gz
postgresql-2a0abe10f3899d5b802f9df6a7ceffc72f513f16.zip
Fix miscalculation of itemsafter in array_set_slice().
If the slice to be assigned to was before the existing array lower bound (requiring at least one null element to spring into existence to fill the gap), the code miscalculated how many entries needed to be copied from the old array's null bitmap. This could result in trashing the array's data area (as seen in bug #5840 from Karsten Loesing), or worse. This has been broken since we first allowed the behavior of assigning to non-adjacent slices, in 8.2. Back-patch to all affected versions.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 4d328d5ce1e..536c4a7ea4a 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -2426,6 +2426,7 @@ array_set_slice(ArrayType *array,
{
/*
* here we must allow for possibility of slice larger than orig array
+ * and/or not adjacent to orig array subscripts
*/
int oldlb = ARR_LBOUND(array)[0];
int oldub = oldlb + ARR_DIMS(array)[0] - 1;
@@ -2434,10 +2435,12 @@ array_set_slice(ArrayType *array,
char *oldarraydata = ARR_DATA_PTR(array);
bits8 *oldarraybitmap = ARR_NULLBITMAP(array);
+ /* count/size of old array entries that will go before the slice */
itemsbefore = Min(slicelb, oldub + 1) - oldlb;
lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
itemsbefore,
elmlen, elmbyval, elmalign);
+ /* count/size of old array entries that will be replaced by slice */
if (slicelb > sliceub)
{
nolditems = 0;
@@ -2451,7 +2454,8 @@ array_set_slice(ArrayType *array,
nolditems,
elmlen, elmbyval, elmalign);
}
- itemsafter = oldub - sliceub;
+ /* count/size of old array entries that will go after the slice */
+ itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
lenafter = olddatasize - lenbefore - olditemsize;
}