Don't use abort(3) in libpq's fe-print.c.
authorTom Lane <[email protected]>
Mon, 28 Jun 2021 18:17:41 +0000 (14:17 -0400)
committerTom Lane <[email protected]>
Mon, 28 Jun 2021 18:17:41 +0000 (14:17 -0400)
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

index fc7d84844e104ff831164308b6ae900f6c968b98..09bbc668843f6dee77b57c770e89f6e551688608 100644 (file)
@@ -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("</table>\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("</table>\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("</tr>", 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] = '-';