Skip to content

Commit 028fc0b

Browse files
committed
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
1 parent 4012281 commit 028fc0b

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

src/backend/utils/adt/arrayfuncs.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,8 +1004,8 @@ array_out(PG_FUNCTION_ARGS)
10041004
int bitmask;
10051005
bool *needquotes,
10061006
needdims = false;
1007+
size_t overall_length;
10071008
int nitems,
1008-
overall_length,
10091009
i,
10101010
j,
10111011
k,
@@ -1078,7 +1078,7 @@ array_out(PG_FUNCTION_ARGS)
10781078
*/
10791079
values = (char **) palloc(nitems * sizeof(char *));
10801080
needquotes = (bool *) palloc(nitems * sizeof(bool));
1081-
overall_length = 1; /* don't forget to count \0 at end. */
1081+
overall_length = 0;
10821082

10831083
p = ARR_DATA_PTR(v);
10841084
bitmap = ARR_NULLBITMAP(v);
@@ -1133,7 +1133,7 @@ array_out(PG_FUNCTION_ARGS)
11331133
/* Count the pair of double quotes, if needed */
11341134
if (needquote)
11351135
overall_length += 2;
1136-
/* and the comma */
1136+
/* and the comma (or other typdelim delimiter) */
11371137
overall_length += 1;
11381138

11391139
/* advance bitmap pointer if any */
@@ -1149,14 +1149,19 @@ array_out(PG_FUNCTION_ARGS)
11491149
}
11501150

11511151
/*
1152-
* count total number of curly braces in output string
1152+
* The very last array element doesn't have a typdelim delimiter after it,
1153+
* but that's OK; that space is needed for the trailing '\0'.
1154+
*
1155+
* Now count total number of curly brace pairs in output string.
11531156
*/
11541157
for (i = j = 0, k = 1; i < ndim; i++)
1155-
k *= dims[i], j += k;
1158+
{
1159+
j += k, k *= dims[i];
1160+
}
1161+
overall_length += 2 * j;
11561162

1163+
/* Format explicit dimensions if required */
11571164
dims_str[0] = '\0';
1158-
1159-
/* add explicit dimensions if required */
11601165
if (needdims)
11611166
{
11621167
char *ptr = dims_str;
@@ -1168,9 +1173,11 @@ array_out(PG_FUNCTION_ARGS)
11681173
}
11691174
*ptr++ = *ASSGN;
11701175
*ptr = '\0';
1176+
overall_length += ptr - dims_str;
11711177
}
11721178

1173-
retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
1179+
/* Now construct the output string */
1180+
retval = (char *) palloc(overall_length);
11741181
p = retval;
11751182

11761183
#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
@@ -1208,21 +1215,26 @@ array_out(PG_FUNCTION_ARGS)
12081215

12091216
for (i = ndim - 1; i >= 0; i--)
12101217
{
1211-
indx[i] = (indx[i] + 1) % dims[i];
1212-
if (indx[i])
1218+
if (++(indx[i]) < dims[i])
12131219
{
12141220
APPENDCHAR(typdelim);
12151221
break;
12161222
}
12171223
else
1224+
{
1225+
indx[i] = 0;
12181226
APPENDCHAR('}');
1227+
}
12191228
}
12201229
j = i;
12211230
} while (j != -1);
12221231

12231232
#undef APPENDSTR
12241233
#undef APPENDCHAR
12251234

1235+
/* Assert that we calculated the string length accurately */
1236+
Assert(overall_length == (p - retval + 1));
1237+
12261238
pfree(values);
12271239
pfree(needquotes);
12281240

0 commit comments

Comments
 (0)