8000 Move return statements out of PG_TRY blocks. · postgres/postgres@0af386b · GitHub
[go: up one dir, main page]

Skip to content

Commit 0af386b

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 4624aad commit 0af386b

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

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

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

729+
PG_TRY();
730+
{
711731
pltname = PyString_FromString(tdata->tg_trigger->tgname);
712732
PyDict_SetItemString(pltdata, "name", pltname);
713733
Py_DECREF(pltname);
@@ -838,12 +858,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
838858
int i;
839859
PyObject *pltarg;
840860

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

0 commit comments

Comments
 (0)
0