postgres.git / summary / log / commit / refs

commit    bbec33c2d0263e367f7ba7d7add768d16861d8a7
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Fri Apr 13 16:53:46 2018 +0000
First released in: 11.0, 9.3.23, 9.4.18, 9.5.13, 9.6.9, 10.4

    In libpq, free any partial query result before collecting a server error.
    
    We'd throw away the partial result anyway after parsing the error message.
    Throwing it away beforehand costs nothing and reduces the risk of
    out-of-memory failure.  Also, at least in systems that behave like
    glibc/Linux, if the partial result was very large then the error PGresult
    would get allocated at high heap addresses, preventing the heap storage
    used by the partial result from being released to the OS until the error
    PGresult is freed.
    
    In psql >= 9.6, we hold onto the error PGresult until another error is
    received (for \errverbose), so that this behavior causes a seeming
    memory leak to persist for awhile, as in a recent complaint from
    Darafei Praliaskouski.  This is a potential performance regression from
    older versions, justifying back-patching at least that far.  But similar
    behavior may occur in other client applications, so it seems worth just
    back-patching to all supported branches.
    
    Discussion: https://postgr.es/m/CAC8Q8tJ=7cOkPePyAbJE_Pf691t8nDFhJp0KZxHvnq_uicfyVg@mail.gmail.com


src/interfaces/libpq/fe-protocol2.c | 10 +++++++++- src/interfaces/libpq/fe-protocol3.c | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c index cf765bee4fa..48023ef2bee 100644 --- a/src/interfaces/libpq/fe-protocol2.c +++ b/src/interfaces/libpq/fe-protocol2.c @@ -967,6 +967,14 @@ pqGetErrorNotice2(PGconn *conn, bool isError) char *startp; char *splitp; + /* + * If this is an error message, pre-emptively clear any incomplete query + * result we may have. We'd just throw it away below anyway, and + * releasing it before collecting the error might avoid out-of-memory. + */ + if (isError) + pqClearAsyncResult(conn); + /* * Since the message might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended @@ -1039,7 +1047,7 @@ pqGetErrorNotice2(PGconn *conn, bool isError) */ if (isError) { - pqClearAsyncResult(conn); + pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; resetPQExpBuffer(&conn->errorMessage); if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 547934826ed..280b7145895 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -869,6 +869,14 @@ pqGetErrorNotice3(PGconn *conn, bool isError) const char *querytext = NULL; int querypos = 0; + /* + * If this is an error message, pre-emptively clear any incomplete query + * result we may have. We'd just throw it away below anyway, and + * releasing it before collecting the error might avoid out-of-memory. + */ + if (isError) + pqClearAsyncResult(conn); + /* * Since the fields might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended @@ -1030,7 +1038,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError) { if (res) res->errMsg = pqResultStrdup(res, workBuf.data); - pqClearAsyncResult(conn); + pqClearAsyncResult(conn); /* redundant, but be safe */ conn->result = res; if (PQExpBufferDataBroken(workBuf)) printfPQExpBuffer(&conn->errorMessage, [parent: ac8ea0f27f3f]