Move return statements out of PG_TRY blocks.

If we exit a PG_TRY block early via "continue", "break", "goto", or
"return", we'll skip unwinding its exception stack.  This change
moves a couple of such "return" statements in PL/Python out of
PG_TRY blocks.  This was introduced in d0aa965c0a and affects all
supported versions.

We might also be able to add compile-time checks to prevent
recurrence, but that is left as a future exercise.

Reported-by: Mikhail Gribkov, Xing Guo
Author: Xing Guo
Reviewed-by: Michael Paquier, Andres Freund, Tom Lane
Discussion: https://postgr.es/m/CAMEv5_v5Y%2B-D%3DCO1%2Bqoe16sAmgC4sbbQjz%2BUtcHmB6zcgS%2B5Ew%40mail.gmail.com
Discussion: https://postgr.es/m/CACpMh%2BCMsGMRKFzFMm3bYTzQmMU5nfEEoEDU2apJcc4hid36AQ%40mail.gmail.com
Backpatch-through: 11 (all supported versions)
This commit is contained in:
Nathan Bossart 2023-05-03 11:32:43 -07:00
parent f75cec4fff
commit 57d0051706
1 changed files with 37 additions and 19 deletions

View File

@ -411,15 +411,20 @@ static PyObject *
PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
{
PyObject *volatile arg = NULL;
PyObject *volatile args = NULL;
PyObject *args;
int i;
/*
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
* return NULL on failure. We can't return within the PG_TRY block, else
* we'd miss unwinding the exception stack.
*/
args = PyList_New(proc->nargs);
if (!args)
return NULL;
PG_TRY();
{
args = PyList_New(proc->nargs);
if (!args)
return NULL;
for (i = 0; i < proc->nargs; i++)
{
PLyDatumToOb *arginfo = &proc->args[i];
@ -683,19 +688,34 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
*pltlevel,
*pltrelid,
*plttablename,
*plttableschema;
PyObject *pltargs,
*plttableschema,
*pltargs = NULL,
*pytnew,
*pytold;
PyObject *volatile pltdata = NULL;
*pytold,
*pltdata;
char *stroid;
/*
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
* return NULL on failure. We can't return within the PG_TRY block, else
* we'd miss unwinding the exception stack.
*/
pltdata = PyDict_New();
if (!pltdata)
return NULL;
if (tdata->tg_trigger->tgnargs)
{
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
if (!pltargs)
{
Py_DECREF(pltdata);
return NULL;
}
}
PG_TRY();
{
pltdata = PyDict_New();
if (!pltdata)
return NULL;
pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
PyDict_SetItemString(pltdata, "name", pltname);
Py_DECREF(pltname);
@ -835,12 +855,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
int i;
PyObject *pltarg;
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
if (!pltargs)
{
Py_DECREF(pltdata);
return NULL;
}
/* pltargs should have been allocated before the PG_TRY block. */
Assert(pltargs);
for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
{
pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
@ -861,6 +878,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
}
PG_CATCH();
{
Py_XDECREF(pltargs);
Py_XDECREF(pltdata);
PG_RE_THROW();
}