Defend against nulls-in-arrays in contrib/intarray. I may have put in
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Nov 2005 03:00:09 +0000 (03:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Nov 2005 03:00:09 +0000 (03:00 +0000)
more tests than strictly necessary, but did not feel like tracing call
paths in detail ...

contrib/intarray/_int.h
contrib/intarray/_int_bool.c
contrib/intarray/_int_gist.c
contrib/intarray/_int_op.c
contrib/intarray/_int_tool.c
contrib/intarray/_intbig_gist.c

index 702dfaade538cbd9578a3f27134f74f33a14e094..ec09b149733a877fa48bc4f0d5074f64153f0723 100644 (file)
 
 /* useful macros for accessing int4 arrays */
 #define ARRPTR(x)  ( (int4 *) ARR_DATA_PTR(x) )
-#define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
+#define ARRNELEMS(x)  ArrayGetNItems(ARR_NDIM(x), ARR_DIMS(x))
 
-#define ARRISVOID(x) ( (x) ? ( ( ARR_NDIM(x) == NDIM ) ? ( ( ARRNELEMS( x ) ) ? 0 : 1 ) : ( ( ARR_NDIM(x) ) ? ( \
-       ereport(ERROR, \
-                       (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), \
-                        errmsg("array must be one-dimensional, not %d dimensions", ARRNELEMS( x )))) \
-       ,1) : 0 )  ) : 0 )
+/* reject arrays we can't handle; but allow a NULL or empty array */
+#define CHECKARRVALID(x) \
+       do { \
+               if (x) { \
+                       if (ARR_NDIM(x) != NDIM && ARR_NDIM(x) != 0) \
+                               ereport(ERROR, \
+                                               (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), \
+                                                errmsg("array must be one-dimensional"))); \
+                       if (ARR_HASNULL(x)) \
+                               ereport(ERROR, \
+                                               (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
+                                                errmsg("array must not contain nulls"))); \
+               } \
+       } while(0)
+
+#define ARRISVOID(x)  ((x) == NULL || ARRNELEMS(x) == 0)
 
 #define SORT(x) \
        do { \
@@ -52,9 +63,6 @@
 typedef char BITVEC[SIGLEN];
 typedef char *BITVECP;
 
-#define SIGPTR(x)  ( (BITVECP) ARR_DATA_PTR(x) )
-
-
 #define LOOPBYTE(a) \
                for(i=0;i<SIGLEN;i++) {\
                                a;\
index 824dc5b677569018d8a5f64465fb988b946df95e..8e0b913c0137e458fbd76fe6d13dfa237e08130d 100644 (file)
@@ -309,6 +309,7 @@ execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
 {
        CHKVAL          chkval;
 
+       CHECKARRVALID(array);
        chkval.arrb = ARRPTR(array);
        chkval.arre = chkval.arrb + ARRNELEMS(array);
        return execute(
@@ -339,6 +340,7 @@ boolop(PG_FUNCTION_ARGS)
        CHKVAL          chkval;
        bool            result;
 
+       CHECKARRVALID(val);
        if (ARRISVOID(val))
        {
                pfree(val);
index c5f8818aa3d3eaf4574e7f49fde865e66ba521c3..1e26bcef284fc9a123297690ae7177e74e9ea66e 100644 (file)
@@ -44,6 +44,7 @@ g_int_consistent(PG_FUNCTION_ARGS)
        /* XXX are we sure it's safe to scribble on the query object here? */
        /* XXX what about toasted input? */
        /* sort query for fast search, key is already sorted */
+       CHECKARRVALID(query);
        if (ARRISVOID(query))
                PG_RETURN_BOOL(false);
        PREPAREARR(query);
@@ -89,21 +90,30 @@ g_int_union(PG_FUNCTION_ARGS)
 {
        GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
        int                *size = (int *) PG_GETARG_POINTER(1);
-       int4            i;
-       ArrayType  *res;
-       int                     totlen = 0,
+       int4            i,
                           *ptr;
+       ArrayType  *res;
+       int                     totlen = 0;
 
        for (i = 0; i < entryvec->n; i++)
-               totlen += ARRNELEMS(GETENTRY(entryvec, i));
+       {
+               ArrayType *ent = GETENTRY(entryvec, i);
+
+               CHECKARRVALID(ent);
+               totlen += ARRNELEMS(ent);
+       }
 
        res = new_intArrayType(totlen);
        ptr = ARRPTR(res);
 
        for (i = 0; i < entryvec->n; i++)
        {
-               memcpy(ptr, ARRPTR(GETENTRY(entryvec, i)), ARRNELEMS(GETENTRY(entryvec, i)) * sizeof(int4));
-               ptr += ARRNELEMS(GETENTRY(entryvec, i));
+               ArrayType *ent = GETENTRY(entryvec, i);
+               int nel;
+
+               nel = ARRNELEMS(ent);
+               memcpy(ptr, ARRPTR(ent), nel * sizeof(int4));
+               ptr += nel;
        }
 
        QSORT(res, 1);
@@ -130,6 +140,7 @@ g_int_compress(PG_FUNCTION_ARGS)
        if (entry->leafkey)
        {
                r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key);
+               CHECKARRVALID(r);
                PREPAREARR(r);
 
                if (ARRNELEMS(r)>= 2 * MAXNUMRANGE)
@@ -147,6 +158,7 @@ g_int_compress(PG_FUNCTION_ARGS)
            so now we work only with internal keys  */
 
        r = (ArrayType *) PG_DETOAST_DATUM(entry->key);
+       CHECKARRVALID(r);
        if (ARRISVOID(r)) 
        {
                if (r != (ArrayType *) DatumGetPointer(entry->key))
@@ -207,6 +219,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
 
        in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
 
+       CHECKARRVALID(in);
        if (ARRISVOID(in))
                PG_RETURN_POINTER(entry);
 
@@ -280,6 +293,9 @@ g_int_same(PG_FUNCTION_ARGS)
        int4       *da,
                           *db;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (n != ARRNELEMS(b))
        {
                *result = false;
index 70951bfd47a7506394270f8ae959ae3eb2b762a8..7a2065bc214e8ebcd7c2011cd70d712eba1db9d0 100644 (file)
@@ -37,6 +37,8 @@ _int_contains(PG_FUNCTION_ARGS)
        ArrayType  *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
        bool            res;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
        if (ARRISVOID(a) || ARRISVOID(b))
                return FALSE;
 
@@ -71,9 +73,13 @@ _int_same(PG_FUNCTION_ARGS)
        int                *da,
                           *db;
        bool            result;
-       bool            avoid = ARRISVOID(a);
-       bool            bvoid = ARRISVOID(b);
+       bool            avoid;
+       bool            bvoid;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+       avoid = ARRISVOID(a);
+       bvoid = ARRISVOID(b);
        if (avoid || bvoid)
                return (avoid && bvoid) ? TRUE : FALSE;
 
@@ -112,6 +118,8 @@ _int_overlap(PG_FUNCTION_ARGS)
        ArrayType  *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
        bool            result;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
        if (ARRISVOID(a) || ARRISVOID(b))
                return FALSE;
 
@@ -133,6 +141,9 @@ _int_union(PG_FUNCTION_ARGS)
        ArrayType  *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
        ArrayType  *result;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (!ARRISVOID(a))
                SORT(a);
        if (!ARRISVOID(b))
@@ -155,6 +166,8 @@ _int_inter(PG_FUNCTION_ARGS)
        ArrayType  *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
        ArrayType  *result;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
        if (ARRISVOID(a) || ARRISVOID(b))
                PG_RETURN_POINTER(new_intArrayType(0));
 
@@ -197,12 +210,6 @@ Datum              intarray_del_elem(PG_FUNCTION_ARGS);
 Datum          intset_union_elem(PG_FUNCTION_ARGS);
 Datum          intset_subtract(PG_FUNCTION_ARGS);
 
-#define QSORT(a, direction)                                            \
-if (ARRNELEMS(a) > 1)                                          \
-       qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4),      \
-               (direction) ? compASC : compDESC )
-
-
 Datum
 intset(PG_FUNCTION_ARGS)
 {
@@ -213,7 +220,7 @@ Datum
 icount(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
-       int32           count = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+       int32           count = ARRNELEMS(a);
 
        PG_FREE_IF_COPY(a, 0);
        PG_RETURN_INT32(count);
@@ -228,6 +235,7 @@ sort(PG_FUNCTION_ARGS)
        char       *d = (dirstr) ? VARDATA(dirstr) : NULL;
        int                     dir = -1;
 
+       CHECKARRVALID(a);
        if (ARRISVOID(a) || ARRNELEMS(a) < 2)
                PG_RETURN_POINTER(a);
 
@@ -255,6 +263,7 @@ sort_asc(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
 
+       CHECKARRVALID(a);
        if (ARRISVOID(a))
                PG_RETURN_POINTER(a);
        QSORT(a, 1);
@@ -266,6 +275,7 @@ sort_desc(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
 
+       CHECKARRVALID(a);
        if (ARRISVOID(a))
                PG_RETURN_POINTER(a);
        QSORT(a, 0);
@@ -277,6 +287,7 @@ uniq(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
 
+       CHECKARRVALID(a);
        if (ARRISVOID(a) || ARRNELEMS(a) < 2)
                PG_RETURN_POINTER(a);
        a = _int_unique(a);
@@ -287,8 +298,10 @@ Datum
 idx(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
-       int32           result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+       int32           result;
 
+       CHECKARRVALID(a);
+       result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
        if (result)
                result = intarray_match_first(a, PG_GETARG_INT32(1));
        PG_FREE_IF_COPY(a, 0);
@@ -305,6 +318,7 @@ subarray(PG_FUNCTION_ARGS)
        int32           end = 0;
        int32           c;
 
+       CHECKARRVALID(a);
        if (ARRISVOID(a))
        {
                PG_FREE_IF_COPY(a, 0);
@@ -371,22 +385,29 @@ Datum
 intarray_del_elem(PG_FUNCTION_ARGS)
 {
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
-       int32           c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
-       int32      *aa = ARRPTR(a);
+       int32           elem = PG_GETARG_INT32(1);
+       int32           c;
+       int32      *aa;
        int32           n = 0,
                                i;
-       int32           elem = PG_GETARG_INT32(1);
 
-       for (i = 0; i < c; i++)
-               if (aa[i] != elem)
+       CHECKARRVALID(a);
+       if (!ARRISVOID(a))
+       {
+               c = ARRNELEMS(a);
+               aa = ARRPTR(a);
+               for (i = 0; i < c; i++)
                {
-                       if (i > n)
-                               aa[n++] = aa[i];
-                       else
-                               n++;
+                       if (aa[i] != elem)
+                       {
+                               if (i > n)
+                                       aa[n++] = aa[i];
+                               else
+                                       n++;
+                       }
                }
-       if (c > 0)
                a = resize_intArrayType(a, n);
+       }
        PG_RETURN_POINTER(a);
 }
 
@@ -408,8 +429,8 @@ intset_subtract(PG_FUNCTION_ARGS)
        ArrayType  *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
        ArrayType  *b = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
        ArrayType  *result;
-       int32           ca = ARRISVOID(a);
-       int32           cb = ARRISVOID(b);
+       int32           ca;
+       int32           cb;
        int32      *aa,
                           *bb,
                           *r;
@@ -417,6 +438,9 @@ intset_subtract(PG_FUNCTION_ARGS)
                                i = 0,
                                k = 0;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        QSORT(a, 1);
        a = _int_unique(a);
        ca = ARRNELEMS(a);
index 13c5d1e9e243950c12baa88a5f75b2ca49f9a8bb..480e16ed9fe57eebe1a08cb372ea5db64f9a8ca9 100644 (file)
@@ -12,6 +12,9 @@ inner_int_contains(ArrayType *a, ArrayType *b)
        int                *da,
                           *db;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (ARRISVOID(a) || ARRISVOID(b))
                return FALSE;
 
@@ -46,6 +49,9 @@ inner_int_overlap(ArrayType *a, ArrayType *b)
        int                *da,
                           *db;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (ARRISVOID(a) || ARRISVOID(b))
                return FALSE;
 
@@ -78,6 +84,9 @@ inner_int_union(ArrayType *a, ArrayType *b)
        int                     i,
                                j;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (ARRISVOID(a) && ARRISVOID(b))
                return new_intArrayType(0);
        if (ARRISVOID(a))
@@ -130,6 +139,9 @@ inner_int_inter(ArrayType *a, ArrayType *b)
        int                     i,
                                j;
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
+
        if (ARRISVOID(a) || ARRISVOID(b))
                return new_intArrayType(0);
 
@@ -243,7 +255,7 @@ copy_intArrayType(ArrayType *a)
        ArrayType  *r;
 
        r = new_intArrayType(ARRNELEMS(a));
-       memmove(r, a, VARSIZE(a));
+       memmove(r, a, VARSIZE(r));
        return r;
 }
 
@@ -270,6 +282,8 @@ _int_unique(ArrayType *r)
                           *data;
        int                     num = ARRNELEMS(r);
 
+       CHECKARRVALID(r);
+
        if (num < 2)
                return r;
 
@@ -302,7 +316,10 @@ intarray_match_first(ArrayType *a, int32 elem)
                                c,
                                i;
 
-       c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+       CHECKARRVALID(a);
+       if (ARRISVOID(a))
+               return 0;
+       c = ARRNELEMS(a);
        aa = ARRPTR(a);
        for (i = 0; i < c; i++)
                if (aa[i] == elem)
@@ -315,8 +332,10 @@ intarray_add_elem(ArrayType *a, int32 elem)
 {
        ArrayType  *result;
        int32      *r;
-       int32           c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+       int32           c;
 
+       CHECKARRVALID(a);
+       c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
        result = new_intArrayType(c + 1);
        r = ARRPTR(result);
        if (c > 0)
@@ -332,6 +351,8 @@ intarray_concat_arrays(ArrayType *a, ArrayType *b)
        int32           ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
        int32           bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(b);
 
+       CHECKARRVALID(a);
+       CHECKARRVALID(b);
        result = new_intArrayType(ac + bc);
        if (ac)
                memcpy(ARRPTR(result), ARRPTR(a), ac * sizeof(int32));
index 237281aec5b61dba3aa2b4db555c9ed893265916..0064e450ddb9145241cb46d2284656cfe92d9d15 100644 (file)
@@ -66,6 +66,8 @@ _intbig_overlap(GISTTYPE * a, ArrayType *b)
        int                     num = ARRNELEMS(b);
        int4       *ptr = ARRPTR(b);
 
+       CHECKARRVALID(b);
+
        while (num--)
        {
                if (GETBIT(GETSIGN(a), HASHVAL(*ptr)))
@@ -82,6 +84,8 @@ _intbig_contains(GISTTYPE * a, ArrayType *b)
        int                     num = ARRNELEMS(b);
        int4       *ptr = ARRPTR(b);
 
+       CHECKARRVALID(b);
+
        while (num--)
        {
                if (!GETBIT(GETSIGN(a), HASHVAL(*ptr)))
@@ -136,10 +140,17 @@ g_intbig_compress(PG_FUNCTION_ARGS)
                int                     num;
                GISTTYPE   *res = (GISTTYPE *) palloc(CALCGTSIZE(0));
 
-               ARRISVOID(in);
-
-               ptr = ARRPTR(in);
-               num = ARRNELEMS(in);
+               CHECKARRVALID(in);
+               if (ARRISVOID(in))
+               {
+                       ptr = NULL;
+                       num = 0;
+               }
+               else
+               {
+                       ptr = ARRPTR(in);
+                       num = ARRNELEMS(in);
+               }
                memset(res, 0, CALCGTSIZE(0));
                res->len = CALCGTSIZE(0);
 
@@ -492,6 +503,7 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
        }
 
        /* XXX what about toasted input? */
+       CHECKARRVALID(query);
        if (ARRISVOID(query))
                return FALSE;
 
@@ -510,6 +522,8 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
                                BITVECP         dq,
                                                        de;
 
+                               CHECKARRVALID(query);
+
                                memset(qp, 0, sizeof(BITVEC));
 
                                while (num--)
@@ -546,6 +560,8 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
                                BITVECP         dq,
                                                        de;
 
+                               CHECKARRVALID(query);
+
                                memset(qp, 0, sizeof(BITVEC));
 
                                while (num--)