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

Commit ac86310

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 329cacb commit ac86310

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
@@ -1029,8 +1029,8 @@ array_out(PG_FUNCTION_ARGS)
10291029
*/
10301030
bool *needquotes,
10311031
needdims = false;
1032+
size_t overall_length;
10321033
int nitems,
1033-
overall_length,
10341034
i,
10351035
j,
10361036
k,
@@ -1104,7 +1104,7 @@ array_out(PG_FUNCTION_ARGS)
11041104
*/
11051105
values = (char **) palloc(nitems * sizeof(char *));
11061106
needquotes = (bool *) palloc(nitems * sizeof(bool));
1107-
overall_length = 1; /* don't forget to count \0 at end. */
1107+
overall_length = 0;
11081108

11091109
array_iter_setup(&iter, v);
11101110

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

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

1176+
/* Format explicit dimensions if required */
11701177
dims_str[0] = '\0';
1171-
1172-
/* add explicit dimensions if required */
11731178
if (needdims)
11741179
{
11751180
char *ptr = dims_str;
@@ -1181,9 +1186,11 @@ array_out(PG_FUNCTION_ARGS)
11811186
}
11821187
*ptr++ = *ASSGN;
11831188
*ptr = '\0';
1189+
overall_length += ptr - dims_str;
11841190
}
11851191

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

11891196
#define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
@@ -1221,21 +1228,26 @@ array_out(PG_FUNCTION_ARGS)
12211228

12221229
for (i = ndim - 1; i >= 0; i--)
12231230
{
1224-
indx[i] = (indx[i] + 1) % dims[i];
1225-
if (indx[i])
1231+
if (++(indx[i]) < dims[i])
12261232
{
12271233
APPENDCHAR(typdelim);
12281234
break;
12291235
}
12301236
else
1237+
{
1238+
indx[i] = 0;
12311239
APPENDCHAR('}');
1240+
}
12321241
}
12331242
j = i;
12341243
} while (j != -1);
12351244

12361245
#undef APPENDSTR
12371246
#undef APPENDCHAR
12381247

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

0 commit comments

Comments
 (0)