Fix trim_array() for zero-dimensional array argument.
authorTom Lane
Sun, 31 Jul 2022 17:43:17 +0000 (13:43 -0400)
committerTom Lane
Sun, 31 Jul 2022 17:43:17 +0000 (13:43 -0400)
The code tried to access ARR_DIMS(v)[0] and ARR_LBOUND(v)[0]
whether or not those values exist.  This made the range check
on the "n" argument unstable --- it might or might not fail, and
if it did it would report garbage for the allowed upper limit.
These bogus accesses would probably annoy Valgrind, and if you
were very unlucky even lead to SIGSEGV.

Report and fix by Martin Kalcher.  Back-patch to v14 where this
function was added.

Discussion: https://postgr.es/m/baaeb413-b8a8-4656-5757-ef347e5ec11f@aboutsource.net

src/backend/utils/adt/arrayfuncs.c
src/test/regress/expected/arrays.out
src/test/regress/sql/arrays.sql

index 2570e5e6301650322f5b9439bcf69f713ddf6e7a..882bcdceca3d70a3882d2b926d16027bb8e2fcc2 100644 (file)
@@ -6685,7 +6685,7 @@ trim_array(PG_FUNCTION_ARGS)
 {
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    int         n = PG_GETARG_INT32(1);
-   int         array_length = ARR_DIMS(v)[0];
+   int         array_length = (ARR_NDIM(v) > 0) ? ARR_DIMS(v)[0] : 0;
    int16       elmlen;
    bool        elmbyval;
    char        elmalign;
@@ -6705,8 +6705,11 @@ trim_array(PG_FUNCTION_ARGS)
    /* Set all the bounds as unprovided except the first upper bound */
    memset(lowerProvided, false, sizeof(lowerProvided));
    memset(upperProvided, false, sizeof(upperProvided));
-   upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
-   upperProvided[0] = true;
+   if (ARR_NDIM(v) > 0)
+   {
+       upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
+       upperProvided[0] = true;
+   }
 
    /* Fetch the needed information about the element type */
    get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
index ce6f3a65f97485d6af54aeebe9835ab6220809d5..97920f38c2113cafa07d37427cd2ec2a6a441929 100644 (file)
@@ -2445,3 +2445,5 @@ SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
 ERROR:  number of elements to trim must be between 0 and 3
 SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail
 ERROR:  number of elements to trim must be between 0 and 3
+SELECT trim_array(ARRAY[]::int[], 1); -- fail
+ERROR:  number of elements to trim must be between 0 and 0
index f774faf8568419cfe9ab4cc43fb695d749b4355d..791af5c0ce1f36e59afeb41c98a477fe479f7768 100644 (file)
@@ -754,3 +754,4 @@ FROM
 
 SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
 SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail
+SELECT trim_array(ARRAY[]::int[], 1); -- fail