Fix miscalculation of itemsafter in array_set_slice().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jan 2011 17:38:52 +0000 (12:38 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 Jan 2011 17:41:01 +0000 (12:41 -0500)
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.

src/backend/utils/adt/arrayfuncs.c

index 4d328d5ce1e8b085cc00aefb1ec7f9cd9092a667..536c4a7ea4a571f4c7bba6276df5196787bd0c8b 100644 (file)
@@ -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;
    }