Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bfdd02f

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 89f2b64 commit bfdd02f

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
@@ -1030,8 +1030,8 @@ array_out(PG_FUNCTION_ARGS)
10301030
*/
10311031
bool *needquotes,
10321032
needdims = false;
1033+
size_t overall_length;
10331034
int nitems,
1034-
overall_length,
10351035
i,
10361036
j,
10371037
k,
@@ -1105,7 +1105,7 @@ array_out(PG_FUNCTION_ARGS)
11051105
*/
11061106
values = (char **) palloc(nitems * sizeof(char *));
11071107
needquotes = (bool *) palloc(nitems * sizeof(bool));
1108-
overall_length = 1; /* don't forget to count \0 at end. */
1108+
overall_length = 0;
11091109

11101110
array_iter_setup(&iter, v);
11111111

@@ -1158,19 +1158,24 @@ array_out(PG_FUNCTION_ARGS)
11581158
/* Count the pair of double quotes, if needed */
11591159
if (needquote)
11601160
overall_length += 2;
1161-
/* and the comma */
1161+
/* and the comma (or other typdelim delimiter) */
11621162
overall_length += 1;
11631163
}
11641164

11651165
/*
1166-
* count total number of curly braces in output string
1166+
* The very last array element doesn't have a typdelim delimiter after it,
1167+
* but that's OK; that space is needed for the trailing '\0'.
1168+
*
1169+
* Now count total number of curly brace pairs in output string.
11671170
*/
11681171
for (i = j = 0, k = 1; i < ndim; i++)
1169-
k *= dims[i], j += k;
1172+
{
1173+
j += k, k *= dims[i];
1174+
}
1175+
overall_length += 2 * j;
11701176

1177+
/* Format explicit dimensions if required */
11711178
dims_str[0] = '\0';
1172-
1173-
/* add explicit dimensions if required */
11741179
if (needdims)
11751180
{
11761181
char *ptr = dims_str;
@@ -1182,9 +1187,11 @@ array_out(PG_FUNCTION_ARGS)
11821187
}
11831188
*ptr++ = *ASSGN;
11841189
*ptr = '\0';
1190+
overall_length += ptr - dims_str;
11851191
}
11861192

1187-
retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
1193+
/* Now construct the output string */
1194+
retval = (char *) palloc(overall_length);
11881195
p = retval;
11891196

11901197
#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
@@ -1222,21 +1229,26 @@ array_out(PG_FUNCTION_ARGS)
12221229

12231230
for (i = ndim - 1; i >= 0; i--)
12241231
{
1225-
indx[i] = (indx[i] + 1) % dims[i];
1226-
if (indx[i])
1232+
if (++(indx[i]) < dims[i])
12271233
{
12281234
APPENDCHAR(typdelim);
12291235
break;
12301236
}
12311237
else
1238+
{
1239+
indx[i] = 0;
12321240
APPENDCHAR('}');
1241+
}
12331242
}
12341243
j = i;
12351244
} while (j != -1);
12361245

12371246
#undef APPENDSTR
12381247
#undef APPENDCHAR
12391248

1249+
/* Assert that we calculated the string length accurately */
1250+
Assert(overall_length == (p - retval + 1));
1251+
12401252
pfree(values);
12411253
pfree(needquotes);
12421254

0 commit comments

Comments
 (0)