Fix memory leak in pgbench
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 9 Apr 2019 16:46:34 +0000 (12:46 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 9 Apr 2019 16:46:34 +0000 (12:46 -0400)
Commit 25ee70511ec2 introduced a memory leak in pgbench: some PGresult
structs were not being freed during error bailout, because we're now
doing more PQgetResult() calls than previously.  Since there's more
cleanup code outside the discard_response() routine than in it, refactor
the cleanup code, removing the routine.

This has little effect currently, since we abandon processing after
hitting errors, but if we ever get further pgbench features (such as
testing for serializable transactions), it'll matter.

Per Coverity.

Reviewed-by: Michaƫl Paquier
src/bin/pgbench/pgbench.c

index 99529de52a5c7f40e6469b20a8d1e98472298dcf..b67ad5e8231ef4a5a7a57fe27e5f49fa09edf260 100644 (file)
@@ -1214,20 +1214,6 @@ doConnect(void)
        return conn;
 }
 
-/* throw away response from backend */
-static void
-discard_response(CState *state)
-{
-       PGresult   *res;
-
-       do
-       {
-               res = PQgetResult(state->con);
-               if (res)
-                       PQclear(res);
-       } while (res);
-}
-
 /* qsort comparator for Variable array */
 static int
 compareVariableNames(const void *v1, const void *v2)
@@ -2732,6 +2718,7 @@ static bool
 readCommandResponse(CState *st, char *varprefix)
 {
        PGresult   *res;
+       PGresult   *next_res;
        int                     qrynum = 0;
 
        res = PQgetResult(st->con);
@@ -2739,7 +2726,7 @@ readCommandResponse(CState *st, char *varprefix)
        while (res != NULL)
        {
                /* look now at the next result to know whether it is the last */
-               PGresult        *next_res = PQgetResult(st->con);
+               next_res = PQgetResult(st->con);
                bool is_last = (next_res == NULL);
 
                switch (PQresultStatus(res))
@@ -2751,8 +2738,7 @@ readCommandResponse(CState *st, char *varprefix)
                                        fprintf(stderr,
                                                        "client %d script %d command %d query %d: expected one row, got %d\n",
                                                        st->id, st->use_file, st->command, qrynum, 0);
-                                       st->ecnt++;
-                                       return false;
+                                       goto error;
                                }
                                break;
 
@@ -2764,10 +2750,7 @@ readCommandResponse(CState *st, char *varprefix)
                                                fprintf(stderr,
                                                                "client %d script %d command %d query %d: expected one row, got %d\n",
                                                                st->id, st->use_file, st->command, qrynum, PQntuples(res));
-                                               st->ecnt++;
-                                               PQclear(res);
-                                               discard_response(st);
-                                               return false;
+                                               goto error;
                                        }
 
                                        /* store results into variables */
@@ -2788,10 +2771,7 @@ readCommandResponse(CState *st, char *varprefix)
                                                                        "client %d script %d command %d query %d: error storing into variable %s\n",
                                                                        st->id, st->use_file, st->command, qrynum,
                                                                        varname);
-                                                       st->ecnt++;
-                                                       PQclear(res);
-                                                       discard_response(st);
-                                                       return false;
+                                                       goto error;
                                                }
 
                                                if (*varprefix != '\0')
@@ -2807,10 +2787,7 @@ readCommandResponse(CState *st, char *varprefix)
                                                "client %d script %d aborted in command %d query %d: %s",
                                                st->id, st->use_file, st->command, qrynum,
                                                PQerrorMessage(st->con));
-                               st->ecnt++;
-                               PQclear(res);
-                               discard_response(st);
-                               return false;
+                               goto error;
                }
 
                PQclear(res);
@@ -2826,8 +2803,19 @@ readCommandResponse(CState *st, char *varprefix)
        }
 
        return true;
-}
 
+error:
+       st->ecnt++;
+       PQclear(res);
+       PQclear(next_res);
+       do
+       {
+               res = PQgetResult(st->con);
+               PQclear(res);
+       } while (res);
+
+       return false;
+}
 
 /*
  * Parse the argument to a \sleep command, and return the requested amount