From cf1f545bf281d3dcb7b44e6b7f21a9369024fbf0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 28 Jun 2021 14:17:42 -0400 Subject: [PATCH] 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 --- src/interfaces/libpq/fe-print.c | 81 +++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index fc7d84844e..09bbc66884 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -37,7 +37,7 @@ #include "libpq-int.h" -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, @@ -80,12 +80,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) @@ -108,20 +108,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]; @@ -190,7 +183,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) @@ -207,10 +200,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) @@ -264,9 +259,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("\n", fout); } @@ -297,18 +295,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"); if (po->html3 && !po->expanded) fputs("\n", fout); - free(fieldMax); - free(fieldNotNum); - free((void *) fieldNames); + +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 @@ -329,7 +343,7 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) } -static void +static bool do_field(const PQprintOpt *po, const PGresult *res, const int i, const int j, const int fs_len, char **fields, @@ -397,7 +411,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); } @@ -440,6 +454,7 @@ do_field(const PQprintOpt *po, const PGresult *res, } } } + return true; } @@ -467,7 +482,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) @@ -558,8 +573,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("", fout); @@ -609,7 +622,7 @@ PQdisplayTuples(const PGresult *res, if (!fLength) { fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); + return; } for (j = 0; j < nFields; j++) @@ -707,7 +720,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] = '-';