Fix trim_array() for zero-dimensional array argument.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 31 Jul 2022 17:43:17 +0000 (13:43 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
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 fb167f226a094933cf11da61ca1f75078afde231..495e449a9e9a2058f605cf2195b26da3eb00e034 100644 (file)
@@ -6839,7 +6839,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;
@@ -6859,8 +6859,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