Thread: BUG #11712: Empty string as error message from libpq

BUG #11712: Empty string as error message from libpq

From
marko@joh.to
Date:
The following bug has been logged on the website:

Bug reference:      11712
Logged by:          Marko Tiikkaja
Email address:      marko@joh.to
PostgreSQL version: 9.4beta2
Operating system:   OS X
Description:

Hi,

This has been annoying me for a while, but I never got around to reporting
the bug.  Reproduced on 9.1 and just tried against HEAD.  Here it is in all
its glory.

Consider a program similar to the LISTEN/NOTIFY example here:
http://www.postgresql.org/docs/9.3/static/libpq-example.html#LIBPQ-EXAMPLE-2,
but with an added error handling around PQconsumeInput():

        if (PQconsumeInput(conn) != 1) {
            fprintf(stderr,
                    "PQconsumeInput() failed: %s\n",
                    PQerrorMessage(conn));
            PQfinish(conn);
            return;
        }

Now when this program is running without SSL, and the server closes the
network connection, what happens is this:

  PQconsumeInput() failed:

i.e. the error string is empty.  This happens when recv() returns 0 on EOF.
pqsecure_write() says the following: "On failure, this function is
responsible for putting a suitable message into conn->errorMessage", but
apparently it doesn't consider recv() returning 0 a "failure", which I guess
is fine.  However, pqReadData() goes through all the fancy logic of
determining that what happened was really an EOF, and then says the
following:

    /*
     * OK, we are getting a zero read even though select() says ready. This
     * means the connection has been closed.  Cope.  Note that errorMessage
     * has been set already.
     */

But I don't see who's supposed to have been set errorMessage in that case.
I think that might be true for SSL code paths, but it's certainly not true
for the non-SSL ones.

Re: BUG #11712: Empty string as error message from libpq

From
Tom Lane
Date:
marko@joh.to writes:
> Consider a program similar to the LISTEN/NOTIFY example here:
> http://www.postgresql.org/docs/9.3/static/libpq-example.html#LIBPQ-EXAMPLE-2,
> but with an added error handling around PQconsumeInput():

>         if (PQconsumeInput(conn) != 1) {
>             fprintf(stderr,
>                     "PQconsumeInput() failed: %s\n",
>                     PQerrorMessage(conn));
>             PQfinish(conn);
>             return;
>         }

> Now when this program is running without SSL, and the server closes the
> network connection, what happens is this:

>   PQconsumeInput() failed:

> i.e. the error string is empty.  This happens when recv() returns 0 on EOF.

Hmm.  I wonder why we're not getting ECONNRESET, since surely the TCP
stack knows the other end is dead?  Anyway, it looks to me like the
best fix is just to set an error message, ie copy this bit

            printfPQExpBuffer(&conn->errorMessage,
                              libpq_gettext(
                                "server closed the connection unexpectedly\n"
                   "\tThis probably means the server terminated abnormally\n"
                             "\tbefore or while processing the request.\n"));

right before definitelyFailed:.  For the goto's leading to that label,
it's reasonable to expect that lower-level code set the errorMessage,
but this will not have happened when pqsecure_read returns zero, since
the whole point is that it doesn't know there's anything wrong.

            regards, tom lane