Fix plpgsql to avoid reference to already-freed memory when returning a
authorTom Lane <[email protected]>
Thu, 19 Apr 2007 16:33:32 +0000 (16:33 +0000)
committerTom Lane <[email protected]>
Thu, 19 Apr 2007 16:33:32 +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 3a381e16b6fae20f2ea58fbf9bc26cc7b7cd4f20..3bd3bbd3dd84a314f5752c2a9b0d74a4ea760ed1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.180.2.4 2007/02/08 18:37:43 tgl Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.180.2.5 2007/04/19 16:33:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -951,6 +951,25 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
            /* Run the block's statements */
            rc = exec_stmts(estate, block->body);
 
+           /*
+            * 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);