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--)