]> granicus.if.org Git - postgresql/commitdiff
libpq was not consistently checking for memory allocation failures. This
authorNeil Conway <neilc@samurai.com>
Sun, 12 Jun 2005 00:00:21 +0000 (00:00 +0000)
committerNeil Conway <neilc@samurai.com>
Sun, 12 Jun 2005 00:00:21 +0000 (00:00 +0000)
patch adds missing checks to the call sites of malloc(), strdup(),
PQmakeEmptyPGresult(), pqResultAlloc(), and pqResultStrdup(), and updates
the documentation. Per original report from Volkan Yazici about
PQmakeEmptyPGresult() not checking for malloc() failure.

doc/src/sgml/libpq.sgml
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c
src/interfaces/libpq/fe-print.c
src/interfaces/libpq/fe-protocol2.c
src/interfaces/libpq/fe-protocol3.c
src/interfaces/libpq/libpq-int.h

index be92de3e701ef3624644e49aa4413e6b99afd0f4..fe15c2b1bb353ae321acbb9963787ee4210ea0c5 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.184 2005/06/10 03:02:01 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.185 2005/06/12 00:00:20 neilc Exp $
 -->
 
  <chapter id="libpq">
@@ -581,14 +581,15 @@ typedef struct
 </para>
 
 <para>
-   Returns a connection options array.  This may
-   be used to determine all possible <function>PQconnectdb</function> options and their
+   Returns a connection options array.  This may be used to determine
+   all possible <function>PQconnectdb</function> options and their
    current default values.  The return value points to an array of
-   <structname>PQconninfoOption</structname> structures, which ends with an entry having a null
-   <structfield>keyword</> pointer.  Note that the current default values
-   (<structfield>val</structfield> fields)
-   will depend on environment variables and other context.
-   Callers must treat the connection options data as read-only.
+   <structname>PQconninfoOption</structname> structures, which ends
+   with an entry having a null <structfield>keyword</> pointer.  The
+   null pointer is returned if memory could not be allocated. Note that
+   the current default values (<structfield>val</structfield> fields)
+   will depend on environment variables and other context.  Callers
+   must treat the connection options data as read-only.
    </para>
 
    <para>
@@ -1651,18 +1652,22 @@ void PQclear(PGresult *res);
 <para>
           Constructs an empty <structname>PGresult</structname> object with the given status.
 <synopsis>
-PGresultPQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
+PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
 </synopsis>
 </para>
 
 <para>
-This is <application>libpq</>'s internal function to allocate and initialize an empty
-<structname>PGresult</structname> object.  It is exported because some applications find it
-useful to generate result objects (particularly objects with error
-status) themselves.  If <parameter>conn</parameter> is not null and <parameter>status</> indicates an error,
-the current error message of the specified connection is copied into the <structname>PGresult</structname>.
-Note that <function>PQclear</function> should eventually be called on the object, just
-as with a <structname>PGresult</structname> returned by <application>libpq</application> itself.
+This is <application>libpq</>'s internal function to allocate and
+initialize an empty <structname>PGresult</structname> object.  This
+function returns NULL if memory could not be allocated. It is exported
+because some applications find it useful to generate result objects
+(particularly objects with error status) themselves.  If
+<parameter>conn</parameter> is not null and <parameter>status</>
+indicates an error, the current error message of the specified
+connection is copied into the <structname>PGresult</structname>.  Note
+that <function>PQclear</function> should eventually be called on the
+object, just as with a <structname>PGresult</structname> returned by
+<application>libpq</application> itself.
 </para>
 </listitem>
 </varlistentry>
@@ -2266,15 +2271,15 @@ unsigned char *PQescapeBytea(const unsigned char *from,
   <para>
    <function>PQescapeBytea</> returns an escaped version of the
    <parameter>from</parameter> parameter binary string in memory
-   allocated with <function>malloc()</>.  This memory must be freed
-   using <function>PQfreemem</> when the result is no longer needed.
-   The return string has all special characters replaced so that they
-   can be properly processed by the
-   <productname>PostgreSQL</productname> string literal parser, and
-   the <type>bytea</type> input function. A terminating zero byte is
-   also added.  The single quotes that must surround
-   <productname>PostgreSQL</productname> string literals are not part
-   of the result string.
+   allocated with <function>malloc()</> (a null pointer is returned if
+   memory could not be allocated).  This memory must be freed using
+   <function>PQfreemem</> when the result is no longer needed.  The
+   return string has all special characters replaced so that they can
+   be properly processed by the <productname>PostgreSQL</productname>
+   string literal parser, and the <type>bytea</type> input function. A
+   terminating zero byte is also added.  The single quotes that must
+   surround <productname>PostgreSQL</productname> string literals are
+   not part of the result string.
   </para>
   </listitem>
   </varlistentry>
index 979f5cd073548f9f58667717edf87bf6a583e1c6..13958b9ad3bdbc3905bd88f2e7abce2e5e379479 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.309 2005/06/10 04:01:36 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.310 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -368,6 +368,8 @@ connectOptions1(PGconn *conn, const char *conninfo)
         *
         * Don't put anything cute here --- intelligence should be in
         * connectOptions2 ...
+        *
+        * XXX: probably worth checking strdup() return value here...
         */
        tmp = conninfo_getval(connOptions, "hostaddr");
        conn->pghostaddr = tmp ? strdup(tmp) : NULL;
@@ -459,7 +461,6 @@ connectOptions2(PGconn *conn)
        }
 
 #ifdef NOT_USED
-
        /*
         * parse dbName to get all additional info in it, if any
         */
@@ -2167,11 +2168,9 @@ closePGconn(PGconn *conn)
 }
 
 /*
-   PQfinish:
-         properly close a connection to the backend
-         also frees the PGconn data structure so it shouldn't be re-used
-         after this
-*/
+ * PQfinish: properly close a connection to the backend. Also frees
+ * the PGconn data structure so it shouldn't be re-used after this.
+ */
 void
 PQfinish(PGconn *conn)
 {
@@ -2182,10 +2181,10 @@ PQfinish(PGconn *conn)
        }
 }
 
-/* PQreset :
-   resets the connection to the backend
-   closes the existing connection and makes a new one
-*/
+/*
+ * PQreset: resets the connection to the backend by closing the
+ * existing connection and creating a new one.
+ */
 void
 PQreset(PGconn *conn)
 {
@@ -2199,11 +2198,12 @@ PQreset(PGconn *conn)
 }
 
 
-/* PQresetStart :
-   resets the connection to the backend
-   closes the existing connection and makes a new one
-   Returns 1 on success, 0 on failure.
-*/
+/*
+ * PQresetStart:
+ * resets the connection to the backend
+ * closes the existing connection and makes a new one
+ * Returns 1 on success, 0 on failure.
+ */
 int
 PQresetStart(PGconn *conn)
 {
@@ -2218,11 +2218,11 @@ PQresetStart(PGconn *conn)
 }
 
 
-/* PQresetPoll :
-   resets the connection to the backend
-   closes the existing connection and makes a new one
-*/
-
+/*
+ * PQresetPoll:
+ * resets the connection to the backend
+ * closes the existing connection and makes a new one
+ */
 PostgresPollingStatusType
 PQresetPoll(PGconn *conn)
 {
@@ -2514,7 +2514,7 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
         * location to find our config files.
         */
        snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf",
-                  getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
+                        getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
 
        if (service != NULL)
        {
@@ -2802,7 +2802,14 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
                if (option->val)
                        free(option->val);
                option->val = strdup(pval);
-
+               if (!option->val)
+               {
+                       printfPQExpBuffer(errorMessage,
+                                                         libpq_gettext("out of memory\n"));
+                       PQconninfoFree(options);
+                       free(buf);
+                       return NULL;
+               }
        }
 
        /* Done with the modifiable input string */
@@ -2835,6 +2842,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
                        if ((tmp = getenv(option->envvar)) != NULL)
                        {
                                option->val = strdup(tmp);
+                               if (!option->val)
+                               {
+                                       printfPQExpBuffer(errorMessage,
+                                                                         libpq_gettext("out of memory\n"));
+                                       PQconninfoFree(options);
+                                       return NULL;
+                               }
                                continue;
                        }
                }
@@ -2846,6 +2860,13 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
                if (option->compiled != NULL)
                {
                        option->val = strdup(option->compiled);
+                       if (!option->val)
+                       {
+                               printfPQExpBuffer(errorMessage,
+                                                                 libpq_gettext("out of memory\n"));
+                               PQconninfoFree(options);
+                               return NULL;
+                       }
                        continue;
                }
 
index 1a01a4c627cab9617eaf9b95fea43b8bccdbc1b8..64ef9cd42821569cdfffcc591b4838803f5f4f9f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.168 2005/06/09 20:01:16 tgl Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.169 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,6 +134,8 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
        PGresult   *result;
 
        result = (PGresult *) malloc(sizeof(PGresult));
+       if (!result)
+               return NULL;
 
        result->ntups = 0;
        result->numAttributes = 0;
@@ -453,7 +455,7 @@ pqPrepareAsyncResult(PGconn *conn)
  * a trailing newline, and should not be more than one line).
  */
 void
-pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
+pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...)
 {
        char            msgBuf[1024];
        va_list         args;
@@ -470,6 +472,8 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
 
        /* Make a PGresult to pass to the notice receiver */
        res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR);
+       if (!res)
+               return;
        res->noticeHooks = *hooks;
 
        /*
@@ -480,15 +484,19 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
        /* XXX should provide a SQLSTATE too? */
 
        /*
-        * Result text is always just the primary message + newline.
+        * Result text is always just the primary message + newline. If we
+        * can't allocate it, don't bother invoking the receiver.
         */
        res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, FALSE);
-       sprintf(res->errMsg, "%s\n", msgBuf);
+       if (res->errMsg)
+       {
+               sprintf(res->errMsg, "%s\n", msgBuf);
 
-       /*
-        * Pass to receiver, then free it.
-        */
-       (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
+               /*
+                * Pass to receiver, then free it.
+                */
+               (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
+       }
        PQclear(res);
 }
 
@@ -1127,8 +1135,9 @@ PQisBusy(PGconn *conn)
 
 /*
  * PQgetResult
- *       Get the next PGresult produced by a query.
- *       Returns NULL if and only if no query work remains.
+ *       Get the next PGresult produced by a query.  Returns NULL if no
+ *       query work remains or an error has occurred (e.g. out of
+ *       memory).
  */
 
 PGresult *
index f3ed41423ecea93d77a5f14ce21b55909727890e..66ad325c52871b025444830becb11ce8413c9375 100644 (file)
@@ -23,7 +23,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.113 2005/02/22 04:42:20 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-misc.c,v 1.114 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,7 +175,8 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
        conn->inCursor += len;
 
        if (conn->Pfdebug)
-               fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"), (unsigned long) len, (int) len, s);
+               fprintf(conn->Pfdebug, libpq_gettext("From backend (%lu)> %.*s\n"),
+                               (unsigned long) len, (int) len, s);
 
        return 0;
 }
index e6740a3d18893511a209bb22a3f8481d7ea2e232..762383feba1bee64285e9815f3f5c397575114c4 100644 (file)
@@ -10,7 +10,7 @@
  * didn't really belong there.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.59 2005/02/22 04:42:20 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-print.c,v 1.60 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,14 +62,11 @@ static void fill(int length, int max, char filler, FILE *fp);
  * details
  *
  * This function should probably be removed sometime since psql
- * doesn't use it anymore. It is unclear to what extend this is used
+ * doesn't use it anymore. It is unclear to what extent this is used
  * by external clients, however.
  */
-
 void
-PQprint(FILE *fout,
-               const PGresult *res,
-               const PQprintOpt *po)
+PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
 {
        int                     nFields;
 
@@ -611,6 +608,12 @@ PQdisplayTuples(const PGresult *res,
        if (fillAlign)
        {
                fLength = (int *) malloc(nFields * sizeof(int));
+               if (!fLength)
+               {
+                       fprintf(stderr, libpq_gettext("out of memory\n"));
+                       exit(1);
+               }
+
                for (j = 0; j < nFields; j++)
                {
                        fLength[j] = strlen(PQfname(res, j));
@@ -705,6 +708,11 @@ PQprintTuples(const PGresult *res,
 
                        width = nFields * 14;
                        tborder = malloc(width + 1);
+                       if (!tborder)
+                       {
+                               fprintf(stderr, libpq_gettext("out of memory\n"));
+                               exit(1);
+                       }
                        for (i = 0; i <= width; i++)
                                tborder[i] = '-';
                        tborder[i] = '\0';
index 2501ef4a603208cc530b364064946b3937ab65a8..b5753dba445789b0672d937b162913a46a62ab18 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.17 2005/05/11 01:26:02 neilc Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.18 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -438,8 +438,12 @@ pqParseInput2(PGconn *conn)
                                        if (pqGets(&conn->workBuffer, conn))
                                                return;
                                        if (conn->result == NULL)
+                                       {
                                                conn->result = PQmakeEmptyPGresult(conn,
                                                                                                           PGRES_COMMAND_OK);
+                                               if (!conn->result)
+                                                       return;
+                                       }
                                        strncpy(conn->result->cmdStatus, conn->workBuffer.data,
                                                        CMDSTATUS_LEN);
                                        checkXactStatus(conn, conn->workBuffer.data);
@@ -572,19 +576,18 @@ pqParseInput2(PGconn *conn)
 static int
 getRowDescriptions(PGconn *conn)
 {
-       PGresult   *result;
+       PGresult   *result = NULL;
        int                     nfields;
        int                     i;
 
        result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
+       if (!result)
+               goto failure;
 
        /* parseInput already read the 'T' label. */
        /* the next two bytes are the number of fields  */
        if (pqGetInt(&(result->numAttributes), 2, conn))
-       {
-               PQclear(result);
-               return EOF;
-       }
+               goto failure;
        nfields = result->numAttributes;
 
        /* allocate space for the attribute descriptors */
@@ -592,6 +595,8 @@ getRowDescriptions(PGconn *conn)
        {
                result->attDescs = (PGresAttDesc *)
                        pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
+               if (!result->attDescs)
+                       goto failure;
                MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
        }
 
@@ -606,10 +611,7 @@ getRowDescriptions(PGconn *conn)
                        pqGetInt(&typid, 4, conn) ||
                        pqGetInt(&typlen, 2, conn) ||
                        pqGetInt(&atttypmod, 4, conn))
-               {
-                       PQclear(result);
-                       return EOF;
-               }
+                       goto failure;
 
                /*
                 * Since pqGetInt treats 2-byte integers as unsigned, we need to
@@ -619,6 +621,8 @@ getRowDescriptions(PGconn *conn)
 
                result->attDescs[i].name = pqResultStrdup(result,
                                                                                                  conn->workBuffer.data);
+               if (!result->attDescs[i].name)
+                       goto failure;
                result->attDescs[i].tableid = 0;
                result->attDescs[i].columnid = 0;
                result->attDescs[i].format = 0;
@@ -630,6 +634,11 @@ getRowDescriptions(PGconn *conn)
        /* Success! */
        conn->result = result;
        return 0;
+
+failure:
+       if (result)
+               PQclear(result);
+       return EOF;
 }
 
 /*
@@ -685,7 +694,11 @@ getAnotherTuple(PGconn *conn, bool binary)
        nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
        /* malloc() only for unusually large field counts... */
        if (nbytes > sizeof(std_bitmap))
+       {
                bitmap = (char *) malloc(nbytes);
+               if (!bitmap)
+                       goto outOfMemory;
+       }
 
        if (pqGetnchar(bitmap, nbytes, conn))
                goto EOFexit;
@@ -758,13 +771,18 @@ outOfMemory:
        pqClearAsyncResult(conn);
        printfPQExpBuffer(&conn->errorMessage,
                                          libpq_gettext("out of memory for query result\n"));
+
+       /*
+        * XXX: if PQmakeEmptyPGresult() fails, there's probably not much
+        * we can do to recover...
+        */
        conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
        conn->asyncStatus = PGASYNC_READY;
        /* Discard the failed message --- good idea? */
        conn->inStart = conn->inEnd;
 
 EOFexit:
-       if (bitmap != std_bitmap)
+       if (bitmap != NULL && bitmap != std_bitmap)
                free(bitmap);
        return EOF;
 }
@@ -780,7 +798,7 @@ EOFexit:
 static int
 pqGetErrorNotice2(PGconn *conn, bool isError)
 {
-       PGresult   *res;
+       PGresult   *res = NULL;
        PQExpBufferData workBuf;
        char       *startp;
        char       *splitp;
@@ -792,10 +810,7 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
         */
        initPQExpBuffer(&workBuf);
        if (pqGets(&workBuf, conn))
-       {
-               termPQExpBuffer(&workBuf);
-               return EOF;
-       }
+               goto failure;
 
        /*
         * Make a PGresult to hold the message.  We temporarily lie about the
@@ -803,8 +818,12 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
         * conn->errorMessage.
         */
        res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
+       if (!res)
+               goto failure;
        res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
        res->errMsg = pqResultStrdup(res, workBuf.data);
+       if (!res->errMsg)
+               goto failure;
 
        /*
         * Break the message into fields.  We can't do very much here, but we
@@ -869,6 +888,12 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
 
        termPQExpBuffer(&workBuf);
        return 0;
+
+failure:
+       if (res)
+               PQclear(res);
+       termPQExpBuffer(&workBuf);
+       return EOF;
 }
 
 /*
index ae8435bf1a7fb857f9c297593868f28fb64c5672..273159f430526295cc8a190c9267e39fb383c01d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.20 2004/12/31 22:03:50 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.21 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,7 +51,7 @@ static int    getParameterStatus(PGconn *conn);
 static int     getNotify(PGconn *conn);
 static int     getCopyStart(PGconn *conn, ExecStatusType copytype);
 static int     getReadyForQuery(PGconn *conn);
-static int build_startup_packet(const PGconn *conn, char *packet,
+static int     build_startup_packet(const PGconn *conn, char *packet,
                                         const PQEnvironmentOption *options);
 
 
@@ -197,8 +197,12 @@ pqParseInput3(PGconn *conn)
                                        if (pqGets(&conn->workBuffer, conn))
                                                return;
                                        if (conn->result == NULL)
+                                       {
                                                conn->result = PQmakeEmptyPGresult(conn,
                                                                                                           PGRES_COMMAND_OK);
+                                               if (!conn->result)
+                                                       return;
+                                       }
                                        strncpy(conn->result->cmdStatus, conn->workBuffer.data,
                                                        CMDSTATUS_LEN);
                                        conn->asyncStatus = PGASYNC_READY;
@@ -215,8 +219,12 @@ pqParseInput3(PGconn *conn)
                                        break;
                                case 'I':               /* empty query */
                                        if (conn->result == NULL)
+                                       {
                                                conn->result = PQmakeEmptyPGresult(conn,
                                                                                                          PGRES_EMPTY_QUERY);
+                                               if (!conn->result)
+                                                       return;
+                                       }
                                        conn->asyncStatus = PGASYNC_READY;
                                        break;
                                case '1':               /* Parse Complete */
@@ -224,8 +232,12 @@ pqParseInput3(PGconn *conn)
                                        if (conn->queryclass == PGQUERY_PREPARE)
                                        {
                                                if (conn->result == NULL)
+                                               {
                                                        conn->result = PQmakeEmptyPGresult(conn,
                                                                                                                           PGRES_COMMAND_OK);
+                                                       if (!conn->result)
+                                                               return;
+                                               }
                                                conn->asyncStatus = PGASYNC_READY;
                                        }
                                        break;
@@ -412,14 +424,13 @@ getRowDescriptions(PGconn *conn)
        int                     i;
 
        result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
+       if (!result)
+               goto failure;
 
        /* parseInput already read the 'T' label and message length. */
        /* the next two bytes are the number of fields  */
        if (pqGetInt(&(result->numAttributes), 2, conn))
-       {
-               PQclear(result);
-               return EOF;
-       }
+               goto failure;
        nfields = result->numAttributes;
 
        /* allocate space for the attribute descriptors */
@@ -427,7 +438,9 @@ getRowDescriptions(PGconn *conn)
        {
                result->attDescs = (PGresAttDesc *)
                        pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
-               MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
+               if (!result->attDescs)
+                       goto failure;
+               MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
        }
 
        /* result->binary is true only if ALL columns are binary */
@@ -451,8 +464,7 @@ getRowDescriptions(PGconn *conn)
                        pqGetInt(&atttypmod, 4, conn) ||
                        pqGetInt(&format, 2, conn))
                {
-                       PQclear(result);
-                       return EOF;
+                       goto failure;
                }
 
                /*
@@ -465,6 +477,8 @@ getRowDescriptions(PGconn *conn)
 
                result->attDescs[i].name = pqResultStrdup(result,
                                                                                                  conn->workBuffer.data);
+               if (!result->attDescs[i].name)
+                       goto failure;
                result->attDescs[i].tableid = tableid;
                result->attDescs[i].columnid = columnid;
                result->attDescs[i].format = format;
@@ -479,6 +493,10 @@ getRowDescriptions(PGconn *conn)
        /* Success! */
        conn->result = result;
        return 0;
+
+failure:
+       PQclear(result);
+       return EOF;
 }
 
 /*
@@ -507,7 +525,7 @@ getAnotherTuple(PGconn *conn, int msgLength)
                        pqResultAlloc(result, nfields * sizeof(PGresAttValue), TRUE);
                if (conn->curTuple == NULL)
                        goto outOfMemory;
-               MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue));
+               MemSet(conn->curTuple, 0, nfields * sizeof(PGresAttValue));
        }
        tup = conn->curTuple;
 
@@ -593,19 +611,11 @@ outOfMemory:
 int
 pqGetErrorNotice3(PGconn *conn, bool isError)
 {
-       PGresult   *res;
+       PGresult   *res = NULL;
        PQExpBufferData workBuf;
        char            id;
        const char *val;
 
-       /*
-        * Make a PGresult to hold the accumulated fields.      We temporarily lie
-        * about the result status, so that PQmakeEmptyPGresult doesn't
-        * uselessly copy conn->errorMessage.
-        */
-       res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
-       res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
-
        /*
         * Since the fields might be pretty long, we create a temporary
         * PQExpBuffer rather than using conn->workBuffer.      workBuffer is
@@ -614,6 +624,16 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
         */
        initPQExpBuffer(&workBuf);
 
+       /*
+        * Make a PGresult to hold the accumulated fields.      We temporarily lie
+        * about the result status, so that PQmakeEmptyPGresult doesn't
+        * uselessly copy conn->errorMessage.
+        */
+       res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
+       if (!res)
+               goto fail;
+       res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
+
        /*
         * Read the fields and save into res.
         */
@@ -702,6 +722,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
        if (isError)
        {
                res->errMsg = pqResultStrdup(res, workBuf.data);
+               if (!res->errMsg)
+                       goto fail;
                pqClearAsyncResult(conn);
                conn->result = res;
                resetPQExpBuffer(&conn->errorMessage);
@@ -825,19 +847,15 @@ getCopyStart(PGconn *conn, ExecStatusType copytype)
        int                     i;
 
        result = PQmakeEmptyPGresult(conn, copytype);
+       if (!result)
+               goto failure;
 
        if (pqGetc(&conn->copy_is_binary, conn))
-       {
-               PQclear(result);
-               return EOF;
-       }
+               goto failure;
        result->binary = conn->copy_is_binary;
        /* the next two bytes are the number of fields  */
        if (pqGetInt(&(result->numAttributes), 2, conn))
-       {
-               PQclear(result);
-               return EOF;
-       }
+               goto failure;
        nfields = result->numAttributes;
 
        /* allocate space for the attribute descriptors */
@@ -845,7 +863,9 @@ getCopyStart(PGconn *conn, ExecStatusType copytype)
        {
                result->attDescs = (PGresAttDesc *)
                        pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
-               MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
+               if (!result->attDescs)
+                       goto failure;
+               MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
        }
 
        for (i = 0; i < nfields; i++)
@@ -853,23 +873,23 @@ getCopyStart(PGconn *conn, ExecStatusType copytype)
                int                     format;
 
                if (pqGetInt(&format, 2, conn))
-               {
-                       PQclear(result);
-                       return EOF;
-               }
+                       goto failure;
 
                /*
                 * Since pqGetInt treats 2-byte integers as unsigned, we need to
                 * coerce these results to signed form.
                 */
                format = (int) ((int16) format);
-
                result->attDescs[i].format = format;
        }
 
        /* Success! */
        conn->result = result;
        return 0;
+
+failure:
+       PQclear(result);
+       return EOF;
 }
 
 /*
index e4692d5d5f63666563a57fecad25ed650e024215..6e14fa8df25ca3399efb33ea33813d91eef2f755 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.101 2005/06/04 20:42:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.102 2005/06/12 00:00:21 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -403,7 +403,7 @@ extern void pqClearAsyncResult(PGconn *conn);
 extern void pqSaveErrorResult(PGconn *conn);
 extern PGresult *pqPrepareAsyncResult(PGconn *conn);
 extern void
-pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
+pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt, ...)
 /* This lets gcc check the format string for consistency. */
 __attribute__((format(printf, 2, 3)));
 extern int     pqAddTuple(PGresult *res, PGresAttValue *tup);