Skip to content

Commit 2496439

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 580df50 commit 2496439

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
@@ -424,15 +424,20 @@ static PyObject *
424424
PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
425425
{
426426
PyObject *volatile arg = NULL;
427-
PyObject *volatile args = NULL;
427+
PyObject *args;
428428
int i;
429429

430+
/*
431+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
432+
* return NULL on failure. We can't return within the PG_TRY block, else
433+
* we'd miss unwinding the exception stack.
434+
*/
435+
args = PyList_New(proc->nargs);
436+
if (!args)
437+
return NULL;
438+
430439
PG_TRY();
431440
{
432-
args = PyList_New(proc->nargs);
433-
if (!args)
434-
return NULL;
435-
436441
for (i = 0; i < proc->nargs; i++)
437442
{
438443
PLyDatumToOb *arginfo = &proc->args[i];
@@ -696,19 +701,34 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
696701
*pltlevel,
697702
*pltrelid,
698703
*plttablename,
699-
*plttableschema;
700-
PyObject *pltargs,
704+
*plttableschema,
705+
*pltargs = NULL,
701706
*pytnew,
702-
*pytold;
703-
PyObject *volatile pltdata = NULL;
707+
*pytold,
708+
*pltdata;
704709
char *stroid;
705710

706-
PG_TRY();
711+
/*
712+
* Make any Py*_New() calls before the PG_TRY block so that we can quickly
713+
* return NULL on failure. We can't return within the PG_TRY block, else
714+
* we'd miss unwinding the exception stack.
715+
*/
716+
pltdata = PyDict_New();
717+
if (!pltdata)
718+
return NULL;
719+
720+
if (tdata->tg_trigger->tgnargs)
707721
{
708-
pltdata = PyDict_New();
709-
if (!pltdata)
722+
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
723+
if (!pltargs)
724+
{
725+
Py_DECREF(pltdata);
710726
return NULL;
727+
}
728+
}
711729

730+
PG_TRY();
731+
{
712732
pltname = PyString_FromString(tdata->tg_trigger->tgname);
713733
PyDict_SetItemString(pltdata, "name", pltname);
714734
Py_DECREF(pltname);
@@ -848,12 +868,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
848868
int i;
849869
PyObject *pltarg;
850870

851-
pltargs = PyList_New(tdata->tg_trigger->tgnargs);
852-
if (!pltargs)
853-
{
854-
Py_DECREF(pltdata);
855-
return NULL;
856-
}
871+
/* pltargs should have been allocated before the PG_TRY block. */
872+
Assert(pltargs);
873+
857874
for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
858875
{
859876
pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
@@ -874,6 +891,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
874891
}
875892
PG_CATCH();
876893
{
894+
Py_XDECREF(pltargs);
877895
Py_XDECREF(pltdata);
878896
PG_RE_THROW();
879897
}

0 commit comments

Comments
 (0)