Fix plpgsql to avoid reference to already-freed memory when returning a
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 19 Apr 2007 16:33:24 +0000 (16:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 19 Apr 2007 16:33:24 +0000 (16:33 +0000)
pass-by-reference data type and the RETURN statement is within an EXCEPTION
block.  Bug introduced by my fix of 2007-01-28 to use per-subtransaction
ExprContexts/EStates; since that wasn't back-patched into older branches,
only 8.2 and HEAD are affected.  Per report from Gary Winslow.

src/pl/plpgsql/src/pl_exec.c

index aa7451d15b3f798f4f6fa04d3214d7009f358786..620b363bda83f94e680ecf599d5cc2f59625afbd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.194 2007/04/16 17:21:23 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.195 2007/04/19 16:33:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -987,6 +987,25 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 
            estate->err_text = gettext_noop("during statement block exit");
 
+           /*
+            * If the block ended with RETURN, we may need to copy the return
+            * value out of the subtransaction eval_context.  This is currently
+            * only needed for scalar result types --- rowtype values will
+            * always exist in the function's own memory context.
+            */
+           if (rc == PLPGSQL_RC_RETURN &&
+               !estate->retisset &&
+               !estate->retisnull &&
+               estate->rettupdesc == NULL)
+           {
+               int16       resTypLen;
+               bool        resTypByVal;
+
+               get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
+               estate->retval = datumCopy(estate->retval,
+                                          resTypByVal, resTypLen);
+           }
+
            /* Commit the inner transaction, return to outer xact context */
            ReleaseCurrentSubTransaction();
            MemoryContextSwitchTo(oldcontext);