diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index eeba7f3..7299bea 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 */ @@ -633,8 +648,7 @@ pqParseInput2(PGconn *conn) /* * parseInput subroutine to read a 'T' (row descriptions) message. * We build a PGresult structure containing the attribute data. - * Returns: 0 if completed message, EOF if error or not enough data - * received yet. + * Returns: 0 if completed message, EOF if not enough data received yet. * * Note that if we run out of data, we have to suspend and reprocess * the message after more data is received. Otherwise, conn->inStart @@ -755,6 +769,10 @@ advance_and_error: conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); conn->asyncStatus = PGASYNC_READY; + if (result && result != conn->result) + PQclear(result); + return 0; + EOFexit: if (result && result != conn->result) PQclear(result); @@ -764,8 +782,7 @@ EOFexit: /* * parseInput subroutine to read a 'B' or 'D' (row data) message. * We fill rowbuf with column pointers and then call the row processor. - * Returns: 0 if completed message, EOF if error or not enough data - * received yet. + * Returns: 0 if completed message, EOF if not enough data received yet. * * Note that if we run out of data, we have to suspend and reprocess * the message after more data is received. Otherwise, conn->inStart @@ -965,14 +982,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 might 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 +1044,22 @@ pqGetErrorNotice2(PGconn *conn, bool isError) pqClearAsyncResult(conn); conn->result = res; resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, res->errMsg); + if (res && !PQExpBufferDataBroken(workBuf)) + 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); diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index a847f08..1a6a2c7 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -204,10 +204,15 @@ pqParseInput3(PGconn *conn) conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) - return; + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory")); + pqSaveErrorResult(conn); + } } - strlcpy(conn->result->cmdStatus, conn->workBuffer.data, - CMDSTATUS_LEN); + if (conn->result) + strlcpy(conn->result->cmdStatus, conn->workBuffer.data, + CMDSTATUS_LEN); conn->asyncStatus = PGASYNC_READY; break; case 'E': /* error return */ @@ -226,7 +231,11 @@ pqParseInput3(PGconn *conn) conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!conn->result) - return; + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory")); + pqSaveErrorResult(conn); + } } conn->asyncStatus = PGASYNC_READY; break; @@ -239,7 +248,11 @@ pqParseInput3(PGconn *conn) conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) - return; + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory")); + pqSaveErrorResult(conn); + } } conn->asyncStatus = PGASYNC_READY; } @@ -306,7 +319,11 @@ pqParseInput3(PGconn *conn) conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) - return; + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory")); + pqSaveErrorResult(conn); + } } conn->asyncStatus = PGASYNC_READY; } @@ -628,7 +645,7 @@ getParamDescriptions(PGconn *conn) result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!result) - goto failure; + goto oom_error; /* parseInput already read the 't' label and message length. */ /* the next two bytes are the number of parameters */ @@ -642,7 +659,7 @@ getParamDescriptions(PGconn *conn) result->paramDescs = (PGresParamDesc *) pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE); if (!result->paramDescs) - goto failure; + goto oom_error; MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc)); } @@ -661,8 +678,18 @@ getParamDescriptions(PGconn *conn) return 0; failure: - PQclear(result); + /* could not read the whole message */ + if (result) + PQclear(result); return EOF; + +oom_error: + if (result) + PQclear(result); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + pqSaveErrorResult(conn); + return 0; } /* @@ -822,11 +849,14 @@ pqGetErrorNotice3(PGconn *conn, bool isError) * Make a PGresult to hold the accumulated fields. We temporarily lie * about the result status, so that PQmakeEmptyPGresult doesn't uselessly * copy conn->errorMessage. + * + * NB: This allocation might 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 fail; - res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; + if (res) + res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; /* * Read the fields and save into res. @@ -966,20 +996,27 @@ pqGetErrorNotice3(PGconn *conn, bool isError) */ if (isError) { - res->errMsg = pqResultStrdup(res, workBuf.data); - if (!res->errMsg) - goto fail; + if (res) + res->errMsg = pqResultStrdup(res, workBuf.data); pqClearAsyncResult(conn); conn->result = res; - appendPQExpBufferStr(&conn->errorMessage, workBuf.data); + if (PQExpBufferDataBroken(workBuf)) + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory")); + else + appendPQExpBufferStr(&conn->errorMessage, workBuf.data); } else { - /* We can cheat a little here and not copy the message. */ - res->errMsg = workBuf.data; - if (res->noticeHooks.noticeRec != NULL) - (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); - PQclear(res); + /* if we couldn't allocate the result set, just discard the NOTICE */ + if (res) + { + /* We can cheat a little here and not copy the message. */ + res->errMsg = workBuf.data; + if (res->noticeHooks.noticeRec != NULL) + (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); + PQclear(res); + } } termPQExpBuffer(&workBuf); @@ -1309,6 +1346,7 @@ getNotify(PGconn *conn) * CopyBothResponse message * * parseInput already read the message type and length. + * Returns 0 if successfully consumed the message, EOF if not enough data. */ static int getCopyStart(PGconn *conn, ExecStatusType copytype) @@ -1319,7 +1357,7 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) result = PQmakeEmptyPGresult(conn, copytype); if (!result) - goto failure; + goto oom_error; if (pqGetc(&conn->copy_is_binary, conn)) goto failure; @@ -1335,7 +1373,7 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) result->attDescs = (PGresAttDesc *) pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); if (!result->attDescs) - goto failure; + goto oom_error; MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); } @@ -1359,8 +1397,17 @@ getCopyStart(PGconn *conn, ExecStatusType copytype) return 0; failure: - PQclear(result); + if (result) + PQclear(result); return EOF; + +oom_error: + if (result) + PQclear(result); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + pqSaveErrorResult(conn); + return 0; } /*