mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Fix possible crash at transaction end when a plpgsql function is used and
then modified within the same transaction. The code was using a linked list of active PLpgSQL_expr structs, which was OK when it was written because plpgsql never released any parse data structures for the life of the backend. But since Neil fixed plpgsql's memory management, elements of the linked list could be freed, leading to crash when the list is chased. Per report and test case from Kris Jurka.
This commit is contained in:
parent
15516c5f0b
commit
b3c47b1e5e
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.3 2006/01/17 17:33:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.4 2006/03/02 05:34:17 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -64,12 +64,8 @@ static const char *const raise_skip_msg = "RAISE";
|
|||||||
* function call creates its own "eval_econtext" ExprContext within this
|
* function call creates its own "eval_econtext" ExprContext within this
|
||||||
* estate. We destroy the estate at transaction shutdown to ensure there
|
* estate. We destroy the estate at transaction shutdown to ensure there
|
||||||
* is no permanent leakage of memory (especially for xact abort case).
|
* is no permanent leakage of memory (especially for xact abort case).
|
||||||
*
|
|
||||||
* If a simple PLpgSQL_expr has been used in the current xact, it is
|
|
||||||
* linked into the active_simple_exprs list.
|
|
||||||
*/
|
*/
|
||||||
static EState *simple_eval_estate = NULL;
|
static EState *simple_eval_estate = NULL;
|
||||||
static PLpgSQL_expr *active_simple_exprs = NULL;
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* Local function forward declarations
|
* Local function forward declarations
|
||||||
@ -3799,6 +3795,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
|
|||||||
{
|
{
|
||||||
Datum retval;
|
Datum retval;
|
||||||
ExprContext *econtext = estate->eval_econtext;
|
ExprContext *econtext = estate->eval_econtext;
|
||||||
|
TransactionId curxid = GetTopTransactionId();
|
||||||
ParamListInfo paramLI;
|
ParamListInfo paramLI;
|
||||||
int i;
|
int i;
|
||||||
Snapshot saveActiveSnapshot;
|
Snapshot saveActiveSnapshot;
|
||||||
@ -3812,13 +3809,11 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
|
|||||||
* Prepare the expression for execution, if it's not been done already in
|
* Prepare the expression for execution, if it's not been done already in
|
||||||
* the current transaction.
|
* the current transaction.
|
||||||
*/
|
*/
|
||||||
if (expr->expr_simple_state == NULL)
|
if (expr->expr_simple_xid != curxid)
|
||||||
{
|
{
|
||||||
expr->expr_simple_state = ExecPrepareExpr(expr->expr_simple_expr,
|
expr->expr_simple_state = ExecPrepareExpr(expr->expr_simple_expr,
|
||||||
simple_eval_estate);
|
simple_eval_estate);
|
||||||
/* Add it to list for cleanup */
|
expr->expr_simple_xid = curxid;
|
||||||
expr->expr_simple_next = active_simple_exprs;
|
|
||||||
active_simple_exprs = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4458,11 +4453,11 @@ exec_simple_check_plan(PLpgSQL_expr *expr)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Yes - this is a simple expression. Mark it as such, and initialize
|
* Yes - this is a simple expression. Mark it as such, and initialize
|
||||||
* state to "not executing".
|
* state to "not valid in current transaction".
|
||||||
*/
|
*/
|
||||||
expr->expr_simple_expr = tle->expr;
|
expr->expr_simple_expr = tle->expr;
|
||||||
expr->expr_simple_state = NULL;
|
expr->expr_simple_state = NULL;
|
||||||
expr->expr_simple_next = NULL;
|
expr->expr_simple_xid = InvalidTransactionId;
|
||||||
/* Also stash away the expression result type */
|
/* Also stash away the expression result type */
|
||||||
expr->expr_simple_type = exprType((Node *) tle->expr);
|
expr->expr_simple_type = exprType((Node *) tle->expr);
|
||||||
}
|
}
|
||||||
@ -4506,8 +4501,7 @@ exec_set_found(PLpgSQL_execstate *estate, bool state)
|
|||||||
* plpgsql_xact_cb --- post-transaction-commit-or-abort cleanup
|
* plpgsql_xact_cb --- post-transaction-commit-or-abort cleanup
|
||||||
*
|
*
|
||||||
* If a simple_eval_estate was created in the current transaction,
|
* If a simple_eval_estate was created in the current transaction,
|
||||||
* it has to be cleaned up, and we have to mark all active PLpgSQL_expr
|
* it has to be cleaned up.
|
||||||
* structs that are using it as no longer active.
|
|
||||||
*
|
*
|
||||||
* XXX Do we need to do anything at subtransaction events?
|
* XXX Do we need to do anything at subtransaction events?
|
||||||
* Maybe subtransactions need to have their own simple_eval_estate?
|
* Maybe subtransactions need to have their own simple_eval_estate?
|
||||||
@ -4516,18 +4510,6 @@ exec_set_found(PLpgSQL_execstate *estate, bool state)
|
|||||||
void
|
void
|
||||||
plpgsql_xact_cb(XactEvent event, void *arg)
|
plpgsql_xact_cb(XactEvent event, void *arg)
|
||||||
{
|
{
|
||||||
PLpgSQL_expr *expr;
|
|
||||||
PLpgSQL_expr *enext;
|
|
||||||
|
|
||||||
/* Mark all active exprs as inactive */
|
|
||||||
for (expr = active_simple_exprs; expr; expr = enext)
|
|
||||||
{
|
|
||||||
enext = expr->expr_simple_next;
|
|
||||||
expr->expr_simple_state = NULL;
|
|
||||||
expr->expr_simple_next = NULL;
|
|
||||||
}
|
|
||||||
active_simple_exprs = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are doing a clean transaction shutdown, free the EState (so that
|
* If we are doing a clean transaction shutdown, free the EState (so that
|
||||||
* any remaining resources will be released correctly). In an abort, we
|
* any remaining resources will be released correctly). In an abort, we
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.65.2.1 2005/11/22 18:23:30 momjian Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.65.2.2 2006/03/02 05:34:17 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -200,9 +200,12 @@ typedef struct PLpgSQL_expr
|
|||||||
/* fields for "simple expression" fast-path execution: */
|
/* fields for "simple expression" fast-path execution: */
|
||||||
Expr *expr_simple_expr; /* NULL means not a simple expr */
|
Expr *expr_simple_expr; /* NULL means not a simple expr */
|
||||||
Oid expr_simple_type;
|
Oid expr_simple_type;
|
||||||
/* if expr is simple AND in use in current xact, these fields are set: */
|
/*
|
||||||
|
* if expr is simple AND in use in current xact, expr_simple_state is
|
||||||
|
* valid. Test validity by seeing if expr_simple_xid matches current XID.
|
||||||
|
*/
|
||||||
ExprState *expr_simple_state;
|
ExprState *expr_simple_state;
|
||||||
struct PLpgSQL_expr *expr_simple_next;
|
TransactionId expr_simple_xid;
|
||||||
/* params to pass to expr */
|
/* params to pass to expr */
|
||||||
int nparams;
|
int nparams;
|
||||||
int params[1]; /* VARIABLE SIZE ARRAY ... must be last */
|
int params[1]; /* VARIABLE SIZE ARRAY ... must be last */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user