Commit fe796ea8 authored by Tom Lane's avatar Tom Lane

Fix an ancient logic error in plpgsql's exec_stmt_block: it thought it could

get away with not (re)initializing a local variable if the variable is marked
"isconst" and not "isnull".  Unfortunately it makes this decision after having
already freed the old value, meaning that something like

   for i in 1..10 loop
     declare c constant text := 'hi there';

leads to subsequent accesses to freed memory, and hence probably crashes.
(In particular, this is why Asif Ali Rehman's bug leads to crash and not
just an unexpectedly-NULL value for SQLERRM: SQLERRM is marked CONSTANT
and so triggers this error.)

The whole thing seems wrong on its face anyway: CONSTANT means that you can't
change the variable inside the block, not that the initializer expression is
guaranteed not to change value across successive block entries.  Hence,
remove the "optimization" instead of trying to fix it.
parent 7ad33ceb
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.187 2007/02/01 19:22:07 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.188 2007/02/08 18:37:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -885,14 +885,15 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
{
PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
/* free any old value, in case re-entering block */
free_var(var);
if (!var->isconst || var->isnull)
{
if (var->default_val == NULL)
{
/* Initially it contains a NULL */
var->value = (Datum) 0;
var->isnull = true;
if (var->default_val == NULL)
{
/*
* If needed, give the datatype a chance to reject
* NULLs, by assigning a NULL to the variable.
......@@ -923,7 +924,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
var->default_val);
}
}
}
break;
case PLPGSQL_DTYPE_REC:
......@@ -1065,7 +1065,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
rc = exec_stmts(estate, exception->action);
free_var(state_var);
state_var->value = (Datum) 0;
free_var(errm_var);
errm_var->value = (Datum) 0;
break;
}
}
......@@ -4867,6 +4869,12 @@ plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
}
}
/*
* free_var --- pfree any pass-by-reference value of the variable.
*
* This should always be followed by some assignment to var->value,
* as it leaves a dangling pointer.
*/
static void
free_var(PLpgSQL_var *var)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment