summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2021-06-28 18:17:42 +0000
committerTom Lane2021-06-28 18:17:42 +0000
commit34c24e5a4337abf9d385558f6beaafb92d3a919d (patch)
tree9fc4fae6be0238d7c0c51640dde7a89e680392af
parentc62c3769ff6134f442c9acb623be4a0d4b17ca11 (diff)
Don't use abort(3) in libpq's fe-print.c.
Causing a core dump on out-of-memory seems pretty unfriendly, and surely is far outside the expected behavior of a general-purpose library. Just print an error message (as we did already) and return. These functions unfortunately don't have an error return convention, but code using them is probably just looking for a quick-n-dirty print method and wouldn't bother to check anyway. Although these functions are semi-deprecated, it still seems appropriate to back-patch this. In passing, also back-patch b90e6cef1, just to reduce cosmetic differences between the branches. Discussion: https://postgr.es/m/3122443.1624735363@sss.pgh.pa.us
-rw-r--r--src/interfaces/libpq/fe-print.c85
1 files changed, 49 insertions, 36 deletions
diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c
index f07adf0b760..1973f9d023d 100644
--- a/src/interfaces/libpq/fe-print.c
+++ b/src/interfaces/libpq/fe-print.c
@@ -38,7 +38,7 @@
#define PQmblenBounded(s, e) strnlen(s, PQmblen(s, e))
-static void do_field(const PQprintOpt *po, const PGresult *res,
+static bool do_field(const PQprintOpt *po, const PGresult *res,
const int i, const int j, const int fs_len,
char **fields,
const int nFields, const char **fieldNames,
@@ -81,12 +81,12 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
unsigned char *fieldNotNum = NULL;
char *border = NULL;
char **fields = NULL;
- const char **fieldNames;
+ const char **fieldNames = NULL;
int fieldMaxLen = 0;
int numFieldName;
int fs_len = strlen(po->fieldSep);
int total_line_length = 0;
- int usePipe = 0;
+ bool usePipe = false;
char *pagerenv;
#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
@@ -109,20 +109,13 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
#endif
nTups = PQntuples(res);
- if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *))))
+ fieldNames = (const char **) calloc(nFields, sizeof(char *));
+ fieldNotNum = (unsigned char *) calloc(nFields, 1);
+ fieldMax = (int *) calloc(nFields, sizeof(int));
+ if (!fieldNames || !fieldNotNum || !fieldMax)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
- }
- if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1)))
- {
- fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
- }
- if (!(fieldMax = (int *) calloc(nFields, sizeof(int))))
- {
- fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ goto exit;
}
for (numFieldName = 0;
po->fieldName && po->fieldName[numFieldName];
@@ -191,7 +184,7 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
fout = popen(pagerenv, "w");
if (fout)
{
- usePipe = 1;
+ usePipe = true;
#ifndef WIN32
#ifdef ENABLE_THREAD_SAFETY
if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
@@ -208,10 +201,12 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
if (!po->expanded && (po->align || po->html3))
{
- if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *))))
+ fields = (char **) calloc((size_t) nTups + 1,
+ nFields * sizeof(char *));
+ if (!fields)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ goto exit;
}
}
else if (po->header && !po->html3)
@@ -265,9 +260,12 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
}
for (j = 0; j < nFields; j++)
- do_field(po, res, i, j, fs_len, fields, nFields,
- fieldNames, fieldNotNum,
- fieldMax, fieldMaxLen, fout);
+ {
+ if (!do_field(po, res, i, j, fs_len, fields, nFields,
+ fieldNames, fieldNotNum,
+ fieldMax, fieldMaxLen, fout))
+ goto exit;
+ }
if (po->html3 && po->expanded)
fputs("</table>\n", fout);
}
@@ -298,16 +296,34 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
for (i = 0; i < nTups; i++)
output_row(fout, po, nFields, fields,
fieldNotNum, fieldMax, border, i);
- free(fields);
- if (border)
- free(border);
}
if (po->header && !po->html3)
fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
(PQntuples(res) == 1) ? "" : "s");
- free(fieldMax);
- free(fieldNotNum);
- free((void *) fieldNames);
+ if (po->html3 && !po->expanded)
+ fputs("</table>\n", fout);
+
+exit:
+ if (fieldMax)
+ free(fieldMax);
+ if (fieldNotNum)
+ free(fieldNotNum);
+ if (border)
+ free(border);
+ if (fields)
+ {
+ /* if calloc succeeded, this shouldn't overflow size_t */
+ size_t numfields = ((size_t) nTups + 1) * (size_t) nFields;
+
+ while (numfields-- > 0)
+ {
+ if (fields[numfields])
+ free(fields[numfields]);
+ }
+ free(fields);
+ }
+ if (fieldNames)
+ free((void *) fieldNames);
if (usePipe)
{
#ifdef WIN32
@@ -324,13 +340,11 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
#endif /* ENABLE_THREAD_SAFETY */
#endif /* WIN32 */
}
- if (po->html3 && !po->expanded)
- fputs("</table>\n", fout);
}
}
-static void
+static bool
do_field(const PQprintOpt *po, const PGresult *res,
const int i, const int j, const int fs_len,
char **fields,
@@ -398,7 +412,7 @@ do_field(const PQprintOpt *po, const PGresult *res,
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ return false;
}
strcpy(fields[i * nFields + j], pval);
}
@@ -441,6 +455,7 @@ do_field(const PQprintOpt *po, const PGresult *res,
}
}
}
+ return true;
}
@@ -468,7 +483,7 @@ do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
if (!border)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ return NULL;
}
p = border;
if (po->standard)
@@ -559,8 +574,6 @@ output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
if (po->standard || field_index + 1 < nFields)
fputs(po->fieldSep, fout);
}
- if (p)
- free(p);
}
if (po->html3)
fputs("</tr>", fout);
@@ -610,7 +623,7 @@ PQdisplayTuples(const PGresult *res,
if (!fLength)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ return;
}
for (j = 0; j < nFields; j++)
@@ -708,7 +721,7 @@ PQprintTuples(const PGresult *res,
if (!tborder)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
- abort();
+ return;
}
for (i = 0; i < width; i++)
tborder[i] = '-';