From: Tom Lane Date: Mon, 15 Aug 2005 19:40:43 +0000 (+0000) Subject: array_in() and array_recv() need to be more paranoid about validating X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=0adf184a4a66355863d6dbc8b0e5c3734637fd7d;p=users%2Fbernd%2Fpostgres.git array_in() and array_recv() need to be more paranoid about validating their OID parameter. It was possible to crash the backend with select array_in('{123}',0,0); because that would bypass the needed step of initializing the workspace. These seem to be the only two places with a problem, though (record_in and record_recv don't have the issue, and the other array functions aren't depending on user-supplied input). Back-patch as far as 7.4; 7.3 does not have the bug. --- diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index f22c3a4600..aeaa4084fa 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -160,7 +160,7 @@ array_in(PG_FUNCTION_ARGS) fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; + my_extra->element_type = ~element_type; } if (my_extra->element_type != element_type) @@ -1175,15 +1175,6 @@ array_recv(PG_FUNCTION_ARGS) } nitems = ArrayGetNItems(ndim, dim); - if (nitems == 0) - { - /* Return empty array */ - retval = (ArrayType *) palloc0(sizeof(ArrayType)); - retval->size = sizeof(ArrayType); - retval->elemtype = element_type; - PG_RETURN_ARRAYTYPE_P(retval); - } - /* * We arrange to look up info about element type, including its * receive conversion proc, only once per series of calls, assuming @@ -1195,7 +1186,7 @@ array_recv(PG_FUNCTION_ARGS) fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; + my_extra->element_type = ~element_type; } if (my_extra->element_type != element_type) @@ -1214,6 +1205,16 @@ array_recv(PG_FUNCTION_ARGS) fcinfo->flinfo->fn_mcxt); my_extra->element_type = element_type; } + + if (nitems == 0) + { + /* Return empty array ... but not till we've validated element_type */ + retval = (ArrayType *) palloc0(sizeof(ArrayType)); + retval->size = sizeof(ArrayType); + retval->elemtype = element_type; + PG_RETURN_ARRAYTYPE_P(retval); + } + typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; @@ -2193,13 +2194,20 @@ array_set_slice(ArrayType *array, * or binary-compatible with, the first argument type of fn(). * * retType: OID of element type of output array. This must be the same as, * or binary-compatible with, the result type of fn(). + * * amstate: workspace for array_map. Must be zeroed by caller before + * first call, and not touched after that. + * + * It is legitimate to pass a freshly-zeroed ArrayMapState on each call, + * but better performance can be had if the state can be preserved across + * a series of calls. * * NB: caller must assure that input array is not NULL. Currently, * any additional parameters passed to fn() may not be specified as NULL * either. */ Datum -array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) +array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType, + ArrayMapState *amstate) { ArrayType *v; ArrayType *result; @@ -2217,12 +2225,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) bool typbyval; char typalign; char *s; - typedef struct - { - ArrayMetaState inp_extra; - ArrayMetaState ret_extra; - } am_extra; - am_extra *my_extra; ArrayMetaState *inp_extra; ArrayMetaState *ret_extra; @@ -2254,22 +2256,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) * only once per series of calls, assuming the element type doesn't * change underneath us. */ - my_extra = (am_extra *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(am_extra)); - my_extra = (am_extra *) fcinfo->flinfo->fn_extra; - inp_extra = &my_extra->inp_extra; - inp_extra->element_type = InvalidOid; - ret_extra = &my_extra->ret_extra; - ret_extra->element_type = InvalidOid; - } - else - { - inp_extra = &my_extra->inp_extra; - ret_extra = &my_extra->ret_extra; - } + inp_extra = &amstate->inp_extra; + ret_extra = &amstate->ret_extra; if (inp_extra->element_type != inpType) { @@ -3101,6 +3089,7 @@ array_type_length_coerce_internal(ArrayType *src, Oid srctype; Oid desttype; FmgrInfo coerce_finfo; + ArrayMapState amstate; } atc_extra; atc_extra *my_extra; FunctionCallInfoData locfcinfo; @@ -3113,10 +3102,9 @@ array_type_length_coerce_internal(ArrayType *src, my_extra = (atc_extra *) fmgr_info->fn_extra; if (my_extra == NULL) { - fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt, - sizeof(atc_extra)); + fmgr_info->fn_extra = MemoryContextAllocZero(fmgr_info->fn_mcxt, + sizeof(atc_extra)); my_extra = (atc_extra *) fmgr_info->fn_extra; - my_extra->srctype = InvalidOid; } if (my_extra->srctype != src_elem_type) @@ -3192,7 +3180,8 @@ array_type_length_coerce_internal(ArrayType *src, locfcinfo.arg[1] = Int32GetDatum(desttypmod); locfcinfo.arg[2] = BoolGetDatum(isExplicit); - return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype); + return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype, + &my_extra->amstate); } /* @@ -3210,6 +3199,7 @@ array_length_coerce(PG_FUNCTION_ARGS) { Oid elemtype; FmgrInfo coerce_finfo; + ArrayMapState amstate; } alc_extra; alc_extra *my_extra; FunctionCallInfoData locfcinfo; @@ -3226,10 +3216,9 @@ array_length_coerce(PG_FUNCTION_ARGS) my_extra = (alc_extra *) fmgr_info->fn_extra; if (my_extra == NULL) { - fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt, - sizeof(alc_extra)); + fmgr_info->fn_extra = MemoryContextAllocZero(fmgr_info->fn_mcxt, + sizeof(alc_extra)); my_extra = (alc_extra *) fmgr_info->fn_extra; - my_extra->elemtype = InvalidOid; } if (my_extra->elemtype != ARR_ELEMTYPE(v)) @@ -3265,7 +3254,8 @@ array_length_coerce(PG_FUNCTION_ARGS) locfcinfo.arg[1] = Int32GetDatum(desttypmod); locfcinfo.arg[2] = BoolGetDatum(isExplicit); - return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v)); + return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v), + &my_extra->amstate); } /*