pgbench: avoid FD_ISSET on an invalid file descriptor
authorAlvaro Herrera <[email protected]>
Mon, 15 Feb 2016 23:33:43 +0000 (20:33 -0300)
committerAlvaro Herrera <[email protected]>
Mon, 15 Feb 2016 23:33:43 +0000 (20:33 -0300)
The original code wasn't careful to test the file descriptor returned by
PQsocket() for an invalid socket.  If an invalid socket did turn up,
that would amount to calling FD_ISSET with fd = -1, whereby undefined
behavior can be invoked.

To fix, test file descriptor for validity and stop further processing if
that fails.

Problem noticed by Coverity.

There is an existing FD_ISSET callsite that does check for invalid
sockets beforehand, but the error message reported by it was
strerror(errno); in testing the aforementioned change, that turns out to
result in "bad socket: Success" which isn't terribly helpful.  Instead
use PQerrorMessage() in both places which is more likely to contain an
useful error message.

Backpatch-through: 9.1.

contrib/pgbench/pgbench.c

index 035024d6f58c269c43eebfd8e3cdd6583d638a83..9e58779cc46618ac3fb2404d3f9696268e9fb2b1 100644 (file)
@@ -2398,7 +2398,7 @@ threadRun(void *arg)
            sock = PQsocket(st->con);
            if (sock < 0)
            {
-               fprintf(stderr, "bad socket: %s\n", strerror(errno));
+               fprintf(stderr, "bad socket: %s", PQerrorMessage(st->con));
                goto done;
            }
 
@@ -2439,11 +2439,21 @@ threadRun(void *arg)
            Command   **commands = sql_files[st->use_file];
            int         prev_ecnt = st->ecnt;
 
-           if (st->con && (FD_ISSET(PQsocket(st->con), &input_mask)
-                           || commands[st->state]->type == META_COMMAND))
+           if (st->con)
            {
-               if (!doCustom(thread, st, &result->conn_time, logfile))
-                   remains--;  /* I've aborted */
+               int         sock = PQsocket(st->con);
+
+               if (sock < 0)
+               {
+                   fprintf(stderr, "bad socket: %s", PQerrorMessage(st->con));
+                   goto done;
+               }
+               if (FD_ISSET(sock, &input_mask) ||
+                   commands[st->state]->type == META_COMMAND)
+               {
+                   if (!doCustom(thread, st, &result->conn_time, logfile))
+                       remains--;  /* I've aborted */
+               }
            }
 
            if (st->ecnt > prev_ecnt && commands[st->state]->type == META_COMMAND)