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

Reply via email to