summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-protocol2.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-07-07 18:37:45 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-07-07 18:45:17 +0300
commit992c6f0d2ca839ba54279fbc1a5d5e01e2e18f58 (patch)
tree91b44b8ac25ffa01a6f71cff7310ff1d1f0867e6 /src/interfaces/libpq/fe-protocol2.c
parent4dac5651b15ded7ce3b730aec936bec957b2c86a (diff)
Improve handling of out-of-memory in libpq.
If an allocation fails in the main message handling loop, pqParseInput3 or pqParseInput2, it should not be treated as "not enough data available yet". Otherwise libpq will wait indefinitely for more data to arrive from the server, and gets stuck forever. This isn't a complete fix - getParamDescriptions and getCopyStart still have the same issue, but it's a step in the right direction. Michael Paquier and me. Backpatch to all supported versions.
Diffstat (limited to 'src/interfaces/libpq/fe-protocol2.c')
-rw-r--r--src/interfaces/libpq/fe-protocol2.c51
1 files changed, 38 insertions, 13 deletions
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 59e4a4973f2..addbd28c5b0 100644
--- a/src/interfaces/libpq/fe-protocol2.c
+++ b/src/interfaces/libpq/fe-protocol2.c
@@ -498,10 +498,17 @@ pqParseInput2(PGconn *conn)
conn->result = PQmakeEmptyPGresult(conn,
PGRES_COMMAND_OK);
if (!conn->result)
- return;
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory"));
+ pqSaveErrorResult(conn);
+ }
+ }
+ if (conn->result)
+ {
+ strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
+ CMDSTATUS_LEN);
}
- strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
- CMDSTATUS_LEN);
checkXactStatus(conn, conn->workBuffer.data);
conn->asyncStatus = PGASYNC_READY;
break;
@@ -522,8 +529,16 @@ pqParseInput2(PGconn *conn)
"unexpected character %c following empty query response (\"I\" message)",
id);
if (conn->result == NULL)
+ {
conn->result = PQmakeEmptyPGresult(conn,
PGRES_EMPTY_QUERY);
+ if (!conn->result)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory"));
+ pqSaveErrorResult(conn);
+ }
+ }
conn->asyncStatus = PGASYNC_READY;
break;
case 'K': /* secret key data from the backend */
@@ -965,14 +980,17 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
* Make a PGresult to hold the message. We temporarily lie about the
* result status, so that PQmakeEmptyPGresult doesn't uselessly copy
* conn->errorMessage.
+ *
+ * NB: This allocation can fail, if you run out of memory. The rest of the
+ * function handles that gracefully, and we still try to set the error
+ * message as the connection's error message.
*/
res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
- if (!res)
- goto failure;
- res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
- res->errMsg = pqResultStrdup(res, workBuf.data);
- if (!res->errMsg)
- goto failure;
+ if (res)
+ {
+ res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
+ res->errMsg = pqResultStrdup(res, workBuf.data);
+ }
/*
* Break the message into fields. We can't do very much here, but we can
@@ -1024,15 +1042,22 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
pqClearAsyncResult(conn);
conn->result = res;
resetPQExpBuffer(&conn->errorMessage);
- appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
+ if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg)
+ appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
+ else
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("out of memory"));
if (conn->xactStatus == PQTRANS_INTRANS)
conn->xactStatus = PQTRANS_INERROR;
}
else
{
- if (res->noticeHooks.noticeRec != NULL)
- (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
- PQclear(res);
+ if (res)
+ {
+ if (res->noticeHooks.noticeRec != NULL)
+ (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
+ PQclear(res);
+ }
}
termPQExpBuffer(&workBuf);