]> granicus.if.org Git - postgresql/commitdiff
Add some code to ensure that we don't lose communication sync due to
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 18 Oct 2004 23:23:19 +0000 (23:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 18 Oct 2004 23:23:19 +0000 (23:23 +0000)
an oversize message, per suggestion from Oliver Jowett.  I'm a bit
dubious that this is a real problem, since the client likely doesn't
have any more space available than the server, but it's not hard to
make it behave according to the protocol intention.

src/backend/libpq/pqcomm.c

index 805577bd77471f237ac246e0befbd2aa2b2fe5ad..f9998bbd7fd7ec8e0dd0b4a70425a988b42b8b8a 100644 (file)
@@ -30,7 +30,7 @@
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.172 2004/09/26 00:26:19 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.173 2004/10/18 23:23:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -777,6 +777,36 @@ pq_getbytes(char *s, size_t len)
        return 0;
 }
 
+/* --------------------------------
+ *             pq_discardbytes         - throw away a known number of bytes
+ *
+ *             same as pq_getbytes except we do not copy the data to anyplace.
+ *             this is used for resynchronizing after read errors.
+ *
+ *             returns 0 if OK, EOF if trouble
+ * --------------------------------
+ */
+static int
+pq_discardbytes(size_t len)
+{
+       size_t          amount;
+
+       while (len > 0)
+       {
+               while (PqRecvPointer >= PqRecvLength)
+               {
+                       if (pq_recvbuf())       /* If nothing in buffer, then recv some */
+                               return EOF;             /* Failed to recv data */
+               }
+               amount = PqRecvLength - PqRecvPointer;
+               if (amount > len)
+                       amount = len;
+               PqRecvPointer += amount;
+               len -= amount;
+       }
+       return 0;
+}
+
 /* --------------------------------
  *             pq_getstring    - get a null terminated string from connection
  *
@@ -867,9 +897,8 @@ pq_getmessage(StringInfo s, int maxlen)
        }
 
        len = ntohl(len);
-       len -= 4;                                       /* discount length itself */
 
-       if (len < 0 ||
+       if (len < 4 ||
                (maxlen > 0 && len > maxlen))
        {
                ereport(COMMERROR,
@@ -878,10 +907,28 @@ pq_getmessage(StringInfo s, int maxlen)
                return EOF;
        }
 
+       len -= 4;                                       /* discount length itself */
+
        if (len > 0)
        {
-               /* Allocate space for message */
-               enlargeStringInfo(s, len);
+               /*
+                * Allocate space for message.  If we run out of room (ridiculously
+                * large message), we will elog(ERROR), but we want to discard the
+                * message body so as not to lose communication sync.
+                */
+               PG_TRY();
+               {
+                       enlargeStringInfo(s, len);
+               }
+               PG_CATCH();
+               {
+                       if (pq_discardbytes(len) == EOF)
+                               ereport(COMMERROR,
+                                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                errmsg("incomplete message from client")));
+                       PG_RE_THROW();
+               }
+               PG_END_TRY();
 
                /* And grab the message */
                if (pq_getbytes(s->data, len) == EOF)