Several libpqxx users have been reporting odd problems with certain error messages generated by libpq. One of them was the inclusion of garbage data.
As it turns out, src/interfaces/libpq/fe-misc.c contains several instances of this construct: printfPQExpBuffer(&conn->ErrorMessage, libpq_gettext("error: %s"), SOCK_STRERROR(SOCK_ERRNO, buffer, sizeof(buffer))); This may occur in other source files as well. On Unix-like systems, SOCK_ERRNO defines to plain errno--which is likely to be overwritten by the libpq_gettext(). I'm attaching a patch that fixes these instances by introducing a named pointer to the SOCK_STRERROR message, initialized before either of the other function calls. Another approach would have been to make libpq_gettext() preserve errno. It's tempting, but I'm not sure it would be valid from a language-lawyer point of view. There is no sequence point between the evaluations of libpq_gettext() and SOCK_STRERROR(). From what I vaguely remember hearing somewhere in the distant past, that means that theoretically they may be evaluated not just in any order but even in parallel. I guess it may actually happen if both inlining and scheduling are sufficiently aggressive. Even if libpq_gettext() is made to restore errno, it will still have to pollute errno at some points during its execution. Jeroen
--- fe-misc.c.org 2005-07-05 17:48:25.000000000 +0700 +++ fe-misc.c 2005-07-05 18:13:03.000000000 +0700 @@ -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 @@ 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; } @@ -590,6 +591,7 @@ conn->inBufSize - conn->inEnd); if (nread < 0) { + const char *errstr; if (SOCK_ERRNO == EINTR) goto retry3; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ @@ -606,9 +608,10 @@ if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif + errstr = SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + errstr); return -1; } if (nread > 0) @@ -681,6 +684,7 @@ conn->inBufSize - conn->inEnd); if (nread < 0) { + const char *errstr; if (SOCK_ERRNO == EINTR) goto retry4; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ @@ -697,9 +701,10 @@ if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif + errstr = SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + errstr); return -1; } if (nread > 0) @@ -759,6 +764,7 @@ if (sent < 0) { + const char *errstr; /* * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If * it's EPIPE or ECONNRESET, assume we've lost the backend @@ -799,9 +805,10 @@ return -1; default: + errstr = SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + errstr); /* We don't assume it's a fatal error... */ conn->outCount = 0; return -1; @@ -986,10 +993,12 @@ if (result < 0) { char sebuf[256]; + const char *errstr; + errstr = SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + errstr); } return result;
---------------------------(end of broadcast)--------------------------- TIP 4: Don't 'kill -9' the postmaster