This patch fixes a read of uninitialized memory in array_out(). The code
was previously doing a strlen() on a stack-allocated char array that,
under some code paths, had never been assigned to. The problem doesn't
appear in REL7_4_STABLE, so there's no need for a backport.

I fixed it by initializing dims_str[0] to '\0' circa line 1018 in
current sources. While doing so I couldn't resist the temptation to fix
a few of arrayfunc.c's crimes against good programming practise, so the
attached patch includes some additional cosmetic improvements. If people
prefer I can just apply the bugfix to HEAD, and save the cleanup till we
branch for 8.1. Comments?

Barring any objections, I'll apply the patch within 24 hours.

-Neil

Index: src/backend/utils/adt/arrayfuncs.c
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/backend/utils/adt/arrayfuncs.c,v
retrieving revision 1.111
diff -c -r1.111 arrayfuncs.c
*** src/backend/utils/adt/arrayfuncs.c	2 Sep 2004 20:05:40 -0000	1.111
--- src/backend/utils/adt/arrayfuncs.c	15 Sep 2004 07:04:58 -0000
***************
*** 896,902 ****
  				k,
  				indx[MAXDIM];
  	int			ndim,
! 			   *dim,
  			   *lb;
  	ArrayMetaState *my_extra;
  
--- 896,902 ----
  				k,
  				indx[MAXDIM];
  	int			ndim,
! 			   *dims,
  			   *lb;
  	ArrayMetaState *my_extra;
  
***************
*** 937,945 ****
  	typioparam = my_extra->typioparam;
  
  	ndim = ARR_NDIM(v);
! 	dim = ARR_DIMS(v);
  	lb = ARR_LBOUND(v);
! 	nitems = ArrayGetNItems(ndim, dim);
  
  	if (nitems == 0)
  	{
--- 937,945 ----
  	typioparam = my_extra->typioparam;
  
  	ndim = ARR_NDIM(v);
! 	dims = ARR_DIMS(v);
  	lb = ARR_LBOUND(v);
! 	nitems = ArrayGetNItems(ndim, dims);
  
  	if (nitems == 0)
  	{
***************
*** 965,978 ****
  	 * (including any overhead such as escaping backslashes), and detect
  	 * whether each item needs double quotes.
  	 */
! 	values = (char **) palloc(nitems * sizeof(char *));
! 	needquotes = (bool *) palloc(nitems * sizeof(bool));
  	p = ARR_DATA_PTR(v);
! 	overall_length = 1;			/* [TRH] don't forget to count \0 at end. */
  	for (i = 0; i < nitems; i++)
  	{
  		Datum		itemvalue;
- 		bool		nq;
  
  		itemvalue = fetch_att(p, typbyval, typlen);
  		values[i] = DatumGetCString(FunctionCall3(&my_extra->proc,
--- 965,978 ----
  	 * (including any overhead such as escaping backslashes), and detect
  	 * whether each item needs double quotes.
  	 */
! 	values = (char **) palloc(nitems * sizeof(*values));
! 	needquotes = (bool *) palloc(nitems * sizeof(*needquotes));
  	p = ARR_DATA_PTR(v);
! 	overall_length = 1;			/* don't forget to count \0 at end. */
! 
  	for (i = 0; i < nitems; i++)
  	{
  		Datum		itemvalue;
  
  		itemvalue = fetch_att(p, typbyval, typlen);
  		values[i] = DatumGetCString(FunctionCall3(&my_extra->proc,
***************
*** 983,1010 ****
  		p = (char *) att_align(p, typalign);
  
  		/* count data plus backslashes; detect chars needing quotes */
! 		nq = (values[i][0] == '\0');	/* force quotes for empty string */
! 		for (tmp = values[i]; *tmp; tmp++)
  		{
  			char		ch = *tmp;
  
  			overall_length += 1;
  			if (ch == '"' || ch == '\\')
  			{
! 				nq = true;
  #ifndef TCL_ARRAYS
  				overall_length += 1;
  #endif
  			}
  			else if (ch == '{' || ch == '}' || ch == typdelim ||
  					 isspace((unsigned char) ch))
! 				nq = true;
  		}
  
- 		needquotes[i] = nq;
- 
  		/* Count the pair of double quotes, if needed */
! 		if (nq)
  			overall_length += 2;
  
  		/* and the comma */
--- 983,1012 ----
  		p = (char *) att_align(p, typalign);
  
  		/* count data plus backslashes; detect chars needing quotes */
! 		if (values[i][0] == '\0')
! 			needquotes[i] = true; /* force quotes for empty string */
! 		else
! 			needquotes[i] = false;
! 
! 		for (tmp = values[i]; *tmp != '\0'; tmp++)
  		{
  			char		ch = *tmp;
  
  			overall_length += 1;
  			if (ch == '"' || ch == '\\')
  			{
! 				needquotes[i] = true;
  #ifndef TCL_ARRAYS
  				overall_length += 1;
  #endif
  			}
  			else if (ch == '{' || ch == '}' || ch == typdelim ||
  					 isspace((unsigned char) ch))
! 				needquotes[i] = true;
  		}
  
  		/* Count the pair of double quotes, if needed */
! 		if (needquotes[i])
  			overall_length += 2;
  
  		/* and the comma */
***************
*** 1014,1020 ****
  	/*
  	 * count total number of curly braces in output string
  	 */
! 	for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
  
  	/* add explicit dimensions if required */
  	if (needdims)
--- 1016,1024 ----
  	/*
  	 * count total number of curly braces in output string
  	 */
! 	for (i = j = 0, k = 1; i < ndim; k *= dims[i++], j += k);
! 
! 	dims_str[0] = '\0';
  
  	/* add explicit dimensions if required */
  	if (needdims)
***************
*** 1023,1029 ****
  
  		for (i = 0; i < ndim; i++)
  		{
! 			sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dim[i] - 1);
  			ptr += strlen(ptr);
  		}
  		*ptr++ = *ASSGN;
--- 1027,1033 ----
  
  		for (i = 0; i < ndim; i++)
  		{
! 			sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);
  			ptr += strlen(ptr);
  		}
  		*ptr++ = *ASSGN;
***************
*** 1039,1045 ****
  	if (needdims)
  		APPENDSTR(dims_str);
  	APPENDCHAR('{');
! 	for (i = 0; i < ndim; indx[i++] = 0);
  	j = 0;
  	k = 0;
  	do
--- 1043,1050 ----
  	if (needdims)
  		APPENDSTR(dims_str);
  	APPENDCHAR('{');
! 	for (i = 0; i < ndim; i++)
! 		indx[i] = 0;
  	j = 0;
  	k = 0;
  	do
***************
*** 1071,1077 ****
  
  		for (i = ndim - 1; i >= 0; i--)
  		{
! 			indx[i] = (indx[i] + 1) % dim[i];
  			if (indx[i])
  			{
  				APPENDCHAR(typdelim);
--- 1076,1082 ----
  
  		for (i = ndim - 1; i >= 0; i--)
  		{
! 			indx[i] = (indx[i] + 1) % dims[i];
  			if (indx[i])
  			{
  				APPENDCHAR(typdelim);
Index: src/backend/utils/adt/arrayutils.c
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/backend/utils/adt/arrayutils.c,v
retrieving revision 1.16
diff -c -r1.16 arrayutils.c
*** src/backend/utils/adt/arrayutils.c	29 Aug 2004 04:12:51 -0000	1.16
--- src/backend/utils/adt/arrayutils.c	15 Sep 2004 07:04:58 -0000
***************
*** 50,65 ****
  
  /* Convert array dimensions into number of elements */
  int
! ArrayGetNItems(int n, int *a)
  {
  	int			i,
  				ret;
  
! 	if (n <= 0)
  		return 0;
  	ret = 1;
! 	for (i = 0; i < n; i++)
! 		ret *= a[i];
  	return ret;
  }
  
--- 50,65 ----
  
  /* Convert array dimensions into number of elements */
  int
! ArrayGetNItems(int ndim, int *dims)
  {
  	int			i,
  				ret;
  
! 	if (ndim <= 0)
  		return 0;
  	ret = 1;
! 	for (i = 0; i < ndim; i++)
! 		ret *= dims[i];
  	return ret;
  }
  
Index: src/include/utils/array.h
===================================================================
RCS file: /home/neilc/private-cvsroot/pgsql-server/src/include/utils/array.h,v
retrieving revision 1.49
diff -c -r1.49 array.h
*** src/include/utils/array.h	29 Aug 2004 04:13:10 -0000	1.49
--- src/include/utils/array.h	15 Sep 2004 07:04:58 -0000
***************
*** 81,88 ****
   *
   * ARR_LBOUND returns a pointer to an array of array lower bounds.
   *
!  * That is: if the third axis of an array has elements 5 through 10, then
!  * ARR_DIMS(a)[2] == 6 and ARR_LBOUND(a)[2] == 5.
   *
   * Unlike C, the default lower bound is 1.
   */
--- 81,88 ----
   *
   * ARR_LBOUND returns a pointer to an array of array lower bounds.
   *
!  * That is: if the third axis of an array has elements 5 through 8, then
!  * ARR_DIMS(a)[2] == 4 and ARR_LBOUND(a)[2] == 5.
   *
   * Unlike C, the default lower bound is 1.
   */
***************
*** 176,182 ****
  
  extern int	ArrayGetOffset(int n, int *dim, int *lb, int *indx);
  extern int	ArrayGetOffset0(int n, int *tup, int *scale);
! extern int	ArrayGetNItems(int n, int *a);
  extern void mda_get_range(int n, int *span, int *st, int *endp);
  extern void mda_get_prod(int n, int *range, int *prod);
  extern void mda_get_offset_values(int n, int *dist, int *prod, int *span);
--- 176,182 ----
  
  extern int	ArrayGetOffset(int n, int *dim, int *lb, int *indx);
  extern int	ArrayGetOffset0(int n, int *tup, int *scale);
! extern int	ArrayGetNItems(int ndims, int *dims);
  extern void mda_get_range(int n, int *span, int *st, int *endp);
  extern void mda_get_prod(int n, int *range, int *prod);
  extern void mda_get_offset_values(int n, int *dist, int *prod, int *span);
---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

Reply via email to