Avoid overflow in fe_utils' printTable()

The original code would miscalculate the total number of cells when the
table to print has more than ~4 billion cells, leading to an unnecessary
error.  Repair by changing some computations to be 64-bits wide.  Add
some necessary overflow checks.

Author: Hongxu Ma <interma@outlook.com>
Discussion: https://postgr.es/m/TYBP286MB0351B057B101C90D7C1239E6B4E2A@TYBP286MB0351.JPNP286.PROD.OUTLOOK.COM
This commit is contained in:
Alvaro Herrera 2023-11-21 14:55:29 +01:00
parent e83aa9f92f
commit 24ea53dcfa
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
2 changed files with 23 additions and 9 deletions

View File

@ -3172,6 +3172,8 @@ void
printTableInit(printTableContent *const content, const printTableOpt *opt,
const char *title, const int ncolumns, const int nrows)
{
uint64 total_cells;
content->opt = opt;
content->title = title;
content->ncolumns = ncolumns;
@ -3179,7 +3181,16 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
content->cells = pg_malloc0((ncolumns * nrows + 1) * sizeof(*content->cells));
total_cells = (uint64) ncolumns * nrows;
/* Catch possible overflow. Using >= here allows adding 1 below */
if (total_cells >= SIZE_MAX / sizeof(*content->cells))
{
fprintf(stderr, _("Cannot print table contents: number of cells %lld is equal to or exceeds maximum %lld.\n"),
(long long int) total_cells,
(long long int) (SIZE_MAX / sizeof(*content->cells)));
exit(EXIT_FAILURE);
}
content->cells = pg_malloc0((total_cells + 1) * sizeof(*content->cells));
content->cellmustfree = NULL;
content->footers = NULL;
@ -3249,15 +3260,17 @@ void
printTableAddCell(printTableContent *const content, char *cell,
const bool translate, const bool mustfree)
{
uint64 total_cells;
#ifndef ENABLE_NLS
(void) translate; /* unused parameter */
#endif
if (content->cellsadded >= content->ncolumns * content->nrows)
total_cells = (uint64) content->ncolumns * content->nrows;
if (content->cellsadded >= total_cells)
{
fprintf(stderr, _("Cannot add cell to table content: "
"total cell count of %d exceeded.\n"),
content->ncolumns * content->nrows);
fprintf(stderr, _("Cannot add cell to table content: total cell count of %lld exceeded.\n"),
(long long int) total_cells);
exit(EXIT_FAILURE);
}
@ -3273,7 +3286,7 @@ printTableAddCell(printTableContent *const content, char *cell,
{
if (content->cellmustfree == NULL)
content->cellmustfree =
pg_malloc0((content->ncolumns * content->nrows + 1) * sizeof(bool));
pg_malloc0((total_cells + 1) * sizeof(bool));
content->cellmustfree[content->cellsadded] = true;
}
@ -3341,9 +3354,10 @@ printTableCleanup(printTableContent *const content)
{
if (content->cellmustfree)
{
int i;
uint64 total_cells;
for (i = 0; i < content->nrows * content->ncolumns; i++)
total_cells = (uint64) content->ncolumns * content->nrows;
for (uint64 i = 0; i < total_cells; i++)
{
if (content->cellmustfree[i])
free(unconstify(char *, content->cells[i]));

View File

@ -171,7 +171,7 @@ typedef struct printTableContent
const char **cells; /* NULL-terminated array of cell content
* strings */
const char **cell; /* Pointer to the last added cell */
long cellsadded; /* Number of cells added this far */
uint64 cellsadded; /* Number of cells added this far */
bool *cellmustfree; /* true for cells that need to be free()d */
printTableFooter *footers; /* Pointer to the first footer */
printTableFooter *footer; /* Pointer to the last added footer */