Skip to content

Commit 7ecdeb5

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 402da70 commit 7ecdeb5

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
@@ -976,8 +976,8 @@ array_out(PG_FUNCTION_ARGS)
976976
int bitmask;
977977
bool *needquotes,
978978
needdims = false;
979+
size_t overall_length;
979980
int nitems,
980-
overall_length,
981981
i,
982982
j,
983983
k,
@@ -1050,7 +1050,7 @@ array_out(PG_FUNCTION_ARGS)
10501050
*/
10511051
values = (char **) palloc(nitems * sizeof(char *));
10521052
needquotes = (bool *) palloc(nitems * sizeof(bool));
1053-
overall_length = 1; /* don't forget to count \0 at end. */
1053+
overall_length = 0;
10541054

10551055
p = ARR_DATA_PTR(v);
10561056
bitmap = ARR_NULLBITMAP(v);
@@ -1105,7 +1105,7 @@ array_out(PG_FUNCTION_ARGS)
11051105
/* Count the pair of double quotes, if needed */
11061106
if (needquote)
11071107
overall_length += 2;
1108-
/* and the comma */
1108+
/* and the comma (or other typdelim delimiter) */
11091109
overall_length += 1;
11101110

11111111
/* advance bitmap pointer if any */
@@ -1121,14 +1121,19 @@ array_out(PG_FUNCTION_ARGS)
11211121
}
11221122

11231123
/*
1124-
* count total number of curly braces in output string
1124+
* The very last array element doesn't have a typdelim delimiter after it,
1125+
* but that's OK; that space is needed for the trailing '\0'.
1126+
*
1127+
* Now count total number of curly brace pairs in output string.
11251128
*/
11261129
for (i = j = 0, k = 1; i < ndim; i++)
1127-
k *= dims[i], j += k;
1130+
{
1131+
j += k, k *= dims[i];
1132+
}
1133+
overall_length += 2 * j;
11281134

1135+
/* Format explicit dimensions if required */
11291136
dims_str[0] = '\0';
1130-
1131-
/* add explicit dimensions if required */
11321137
if (needdims)
11331138
{
11341139
char *ptr = dims_str;
@@ -1140,9 +1145,11 @@ array_out(PG_FUNCTION_ARGS)
11401145
}
11411146
*ptr++ = *ASSGN;
11421147
*ptr = '\0';
1148+
overall_length += ptr - dims_str;
11431149
}
11441150

1145-
retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
1151+
/* Now construct the output string */
1152+
retval = (char *) palloc(overall_length);
11461153
p = retval;
11471154

11481155
#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
@@ -1180,21 +1187,26 @@ array_out(PG_FUNCTION_ARGS)
11801187

11811188
for (i = ndim - 1; i >= 0; i--)
11821189
{
1183-
indx[i] = (indx[i] + 1) % dims[i];
1184-
if (indx[i])
1190+
if (++(indx[i]) < dims[i])
11851191
{
11861192
APPENDCHAR(typdelim);
11871193
break;
11881194
}
11891195
else
1196+
{
1197+
indx[i] = 0;
11901198
APPENDCHAR('}');
1199+
}
11911200
}
11921201
j = i;
11931202
} while (j != -1);
11941203

11951204
#undef APPENDSTR
11961205
#undef APPENDCHAR
11971206

1207+
/* Assert that we calculated the string length accurately */
1208+
Assert(overall_length == (p - retval + 1));
1209+
11981210
pfree(values);
11991211
pfree(needquotes);
12001212

0 commit comments

Comments
 (0)