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 660e854e93f4d06faeedc8cd39a85c3589796afc..55ba9f73deb9988990b190d96f186470aa34ab9c 100644 (file)
@@ -6684,7 +6684,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;
@@ -6704,8 +6704,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 95481ce568afbc0851b880477d87a926b71659b5..4923cf36d6587c0b8450abced8eb39ef3186d595 100644 (file)
@@ -2432,3 +2432,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 3ab7f392be4ccc7c5d788672d5a1955ddb5150c9..5eedc4c3ce4a243329d86b3e048166050fb54d67 100644 (file)
@@ -737,3 +737,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