postgres.git / summary / log / commit / refs

commit    a6f7745a3e7f89deeb45e78a4bc1b7f39b2d699a
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Wed Jun 16 23:30:17 2021 +0000
First released in: 14.0, 9.6.23, 10.18, 11.13, 12.8, 13.4

    Fix plancache refcount leak after error in ExecuteQuery.
    
    When stuffing a plan from the plancache into a Portal, one is
    not supposed to risk throwing an error between GetCachedPlan and
    PortalDefineQuery; if that happens, the plan refcount incremented
    by GetCachedPlan will be leaked.  I managed to break this rule
    while refactoring code in 9dbf2b7d7.  There is no visible
    consequence other than some memory leakage, and since nobody is
    very likely to trigger the relevant error conditions many times
    in a row, it's not surprising we haven't noticed.  Nonetheless,
    it's a bug, so rearrange the order of operations to remove the
    hazard.
    
    Noted on the way to looking for a better fix for bug #17053.
    This mistake is pretty old, so back-patch to all supported
    branches.


src/backend/commands/prepare.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index be7222f0033..cb8ee3f7ed8 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -246,6 +246,17 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, cplan = GetCachedPlan(entry->plansource, paramLI, false, NULL); plan_list = cplan->stmt_list; + /* + * DO NOT add any logic that could possibly throw an error between + * GetCachedPlan and PortalDefineQuery, or you'll leak the plan refcount. + */ + PortalDefineQuery(portal, + NULL, + query_string, + entry->plansource->commandTag, + plan_list, + cplan); + /* * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared * statement is one that produces tuples. Currently we insist that it be @@ -289,13 +300,6 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, count = FETCH_ALL; } - PortalDefineQuery(portal, - NULL, - query_string, - entry->plansource->commandTag, - plan_list, - cplan); - /* * Run the portal as appropriate. */ [parent: 1dc53c914fe8]