summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-09-24 11:30:51 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-09-24 11:30:51 -0400
commitac863108f56b721a63df400086ab26c63b61dc21 (patch)
tree9c686e75a9a1a0f3b18eb7c38cc1abf397901808
parent329cacb902705c44c66098535c61f8e84f6f6ee0 (diff)
Fix over-allocation of space for array_out()'s result string.
array_out overestimated the space needed for its output, possibly by a very substantial amount if the array is multi-dimensional, because of wrong order of operations in the loop that counts the number of curly-brace pairs needed. While the output string is normally short-lived, this could still cause problems in extreme cases. An additional minor error was that it counted one more delimiter than is actually needed. Repair those errors, add an Assert that the space is now correctly calculated, and make some minor improvements in the comments. I also failed to resist the temptation to get rid of an integer modulus operation per array element; a simple comparison is sufficient. This bug dates clear back to Berkeley days, so back-patch to all supported versions. Keiichi Hirobe, minor additional work by me Discussion: https://postgr.es/m/CAH=EFxE9W0tRvQkixR2XJRRCToUYUEDkJZk6tnADXugPBRdcdg@mail.gmail.com
-rw-r--r--src/backend/utils/adt/arrayfuncs.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 5b2ca61c78c..caac4c3c4f0 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -1029,8 +1029,8 @@ array_out(PG_FUNCTION_ARGS)
*/
bool *needquotes,
needdims = false;
+ size_t overall_length;
int nitems,
- overall_length,
i,
j,
k,
@@ -1104,7 +1104,7 @@ array_out(PG_FUNCTION_ARGS)
*/
values = (char **) palloc(nitems * sizeof(char *));
needquotes = (bool *) palloc(nitems * sizeof(bool));
- overall_length = 1; /* don't forget to count \0 at end. */
+ overall_length = 0;
array_iter_setup(&iter, v);
@@ -1157,19 +1157,24 @@ array_out(PG_FUNCTION_ARGS)
/* Count the pair of double quotes, if needed */
if (needquote)
overall_length += 2;
- /* and the comma */
+ /* and the comma (or other typdelim delimiter) */
overall_length += 1;
}
/*
- * count total number of curly braces in output string
+ * The very last array element doesn't have a typdelim delimiter after it,
+ * but that's OK; that space is needed for the trailing '\0'.
+ *
+ * Now count total number of curly brace pairs in output string.
*/
for (i = j = 0, k = 1; i < ndim; i++)
- k *= dims[i], j += k;
+ {
+ j += k, k *= dims[i];
+ }
+ overall_length += 2 * j;
+ /* Format explicit dimensions if required */
dims_str[0] = '\0';
-
- /* add explicit dimensions if required */
if (needdims)
{
char *ptr = dims_str;
@@ -1181,9 +1186,11 @@ array_out(PG_FUNCTION_ARGS)
}
*ptr++ = *ASSGN;
*ptr = '\0';
+ overall_length += ptr - dims_str;
}
- retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
+ /* Now construct the output string */
+ retval = (char *) palloc(overall_length);
p = retval;
#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
@@ -1221,14 +1228,16 @@ array_out(PG_FUNCTION_ARGS)
for (i = ndim - 1; i >= 0; i--)
{
- indx[i] = (indx[i] + 1) % dims[i];
- if (indx[i])
+ if (++(indx[i]) < dims[i])
{
APPENDCHAR(typdelim);
break;
}
else
+ {
+ indx[i] = 0;
APPENDCHAR('}');
+ }
}
j = i;
} while (j != -1);
@@ -1236,6 +1245,9 @@ array_out(PG_FUNCTION_ARGS)
#undef APPENDSTR
#undef APPENDCHAR
+ /* Assert that we calculated the string length accurately */
+ Assert(overall_length == (p - retval + 1));
+
pfree(values);
pfree(needquotes);