Skip to content

Commit 52c9cf3

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 d5de344 commit 52c9cf3

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
@@ -415,15 +415,20 @@ static PyObject *
415415
PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
416416
{
417417
PyObject *volatile arg = NULL;
418-
PyObject *volatile args = NULL;
418+
PyObject *args;
419419
int i;
420420

421+
/*
422+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
423+
* return NULL on failure. We can't return within the PG_TRY block, else
424+
* we'd miss unwinding the exception stack.
425+
*/
426+
args = PyList_New(proc->nargs);
427+
if (!args)
428+
return NULL;
429+
421430
PG_TRY();
422431
{
423-
args = PyList_New(proc->nargs);
424-
if (!args)
425-
return NULL;
426-
427432
for (i = 0; i < proc->nargs; i++)
428433
{
429434
PLyDatumToOb *arginfo = &proc->args[i];
@@ -687,19 +692,34 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
687692
*pltlevel,
688693
*pltrelid,
689694
*plttablename,
690-
*plttableschema;
691-
PyObject *pltargs,
695+
*plttableschema,
696+
*pltargs = NULL,
692697
*pytnew,
693-
*pytold;
694-
PyObject *volatile pltdata = NULL;
698+
*pytold,
699+
*pltdata;
695700
char *stroid;
696701

697-
PG_TRY();
702+
/*
703+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
704+
* return NULL on failure. We can't return within the PG_TRY block, else
705+
* we'd miss unwinding the exception stack.
706+
*/
707+
pltdata = PyDict_New();
708+
if (!pltdata)
709+
return NULL;
710+
711+
if (tdata->tg_trigger->tgnargs)
698712
{
699-
pltdata = PyDict_New();
700-
if (!pltdata)
713+
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
714+
if (!pltargs)
715+
{
716+
Py_DECREF(pltdata);
701717
return NULL;
718+
}
719+
}
702720

721+
PG_TRY();
722+
{
703723
pltname = PyString_FromString(tdata->tg_trigger->tgname);
704724
PyDict_SetItemString(pltdata, "name", pltname);
705725
Py_DECREF(pltname);
@@ -839,12 +859,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
839859
int i;
840860
PyObject *pltarg;
841861

842-
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
843-
if (!pltargs)
844-
{
845-
Py_DECREF(pltdata);
846-
return NULL;
847-
}
862+
/* pltargs should have been allocated before the PG_TRY block. */
863+
Assert(pltargs);
864+
848865
for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
849866
{
850867
pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
@@ -865,6 +882,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
865882
}
866883
PG_CATCH();
867884
{
885+
Py_XDECREF(pltargs);
868886
Py_XDECREF(pltdata);
869887
PG_RE_THROW();
870888
}

0 commit comments

Comments
 (0)