Skip to content

Commit 57d0051

Browse files
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 d0aa965 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)
1 parent f75cec4 commit 57d0051

File tree

1 file changed

+36
-18
lines changed

1 file changed

+36
-18
lines changed

src/pl/plpython/plpy_exec.c

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -411,15 +411,20 @@ static PyObject *
411411
PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
412412
{
413413
PyObject *volatile arg = NULL;
414-
PyObject *volatile args = NULL;
414+
PyObject *args;
415415
int i;
416416

417+
/*
418+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
419+
* return NULL on failure. We can't return within the PG_TRY block, else
420+
* we'd miss unwinding the exception stack.
421+
*/
422+
args = PyList_New(proc->nargs);
423+
if (!args)
424+
return NULL;
425+
417426
PG_TRY();
418427
{
419-
args = PyList_New(proc->nargs);
420-
if (!args)
421-
return NULL;
422-
423428
for (i = 0; i < proc->nargs; i++)
424429
{
425430
PLyDatumToOb *arginfo = &proc->args[i];
@@ -683,19 +688,34 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
683688
*pltlevel,
684689
*pltrelid,
685690
*plttablename,
686-
*plttableschema;
687-
PyObject *pltargs,
691+
*plttableschema,
692+
*pltargs = NULL,
688693
*pytnew,
689-
*pytold;
690-
PyObject *volatile pltdata = NULL;
694+
*pytold,
695+
*pltdata;
691696
char *stroid;
692697

693-
PG_TRY();
698+
/*
699+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
700+
* return NULL on failure. We can't return within the PG_TRY block, else
701+
* we'd miss unwinding the exception stack.
702+
*/
703+
pltdata = PyDict_New();
704+
if (!pltdata)
705+
return NULL;
706+
707+
if (tdata->tg_trigger->tgnargs)
694708
{
695-
pltdata = PyDict_New();
696-
if (!pltdata)
709+
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
710+
if (!pltargs)
711+
{
712+
Py_DECREF(pltdata);
697713
return NULL;
714+
}
715+
}
698716

717+
PG_TRY();
718+
{
699719
pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
700720
PyDict_SetItemString(pltdata, "name", pltname);
701721
Py_DECREF(pltname);
@@ -835,12 +855,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
835855
int i;
836856
PyObject *pltarg;
837857

838-
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
839-
if (!pltargs)
840-
{
841-
Py_DECREF(pltdata);
842-
return NULL;
843-
}
858+
/* pltargs should have been allocated before the PG_TRY block. */
859+
Assert(pltargs);
860+
844861
for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
845862
{
846863
pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
@@ -861,6 +878,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
861878
}
862879
PG_CATCH();
863880
{
881+
Py_XDECREF(pltargs);
864882
Py_XDECREF(pltdata);
865883
PG_RE_THROW();
866884
}

0 commit comments

Comments
 (0)