From 8ef289dba12f16f3692c235863a887672499a5d9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 19 Nov 2005 03:00:09 +0000 Subject: [PATCH] Defend against nulls-in-arrays in contrib/intarray. I may have put in more tests than strictly necessary, but did not feel like tracing call paths in detail ... --- contrib/intarray/_int.h | 26 ++++++++----- contrib/intarray/_int_bool.c | 2 + contrib/intarray/_int_gist.c | 28 +++++++++++--- contrib/intarray/_int_op.c | 68 ++++++++++++++++++++++----------- contrib/intarray/_int_tool.c | 27 +++++++++++-- contrib/intarray/_intbig_gist.c | 24 ++++++++++-- 6 files changed, 131 insertions(+), 44 deletions(-) diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h index 702dfaade5..ec09b14973 100644 --- a/contrib/intarray/_int.h +++ b/contrib/intarray/_int.h @@ -19,13 +19,24 @@ /* 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;in; 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; diff --git a/contrib/intarray/_int_op.c b/contrib/intarray/_int_op.c index 70951bfd47..7a2065bc21 100644 --- a/contrib/intarray/_int_op.c +++ b/contrib/intarray/_int_op.c @@ -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); diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c index 13c5d1e9e2..480e16ed9f 100644 --- a/contrib/intarray/_int_tool.c +++ b/contrib/intarray/_int_tool.c @@ -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)); diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c index 237281aec5..0064e450dd 100644 --- a/contrib/intarray/_intbig_gist.c +++ b/contrib/intarray/_intbig_gist.c @@ -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--) -- 2.40.0