diff options
author | Nathan Bossart <nathan@postgresql.org> | 2023-05-03 11:32:43 -0700 |
---|---|---|
committer | Nathan Bossart <nathan@postgresql.org> | 2023-05-04 16:26:05 -0700 |
commit | 24964394a972d0e7b030bf02a600bceea0be72d3 (patch) | |
tree | 3e8edafa3a21672e8eae09143f6577c1c9a458df | |
parent | 580df507896351a0ebb5a09c2c84c0eac7b6740f (diff) | |
download | postgresql-24964394a972d0e7b030bf02a600bceea0be72d3.tar.gz postgresql-24964394a972d0e7b030bf02a600bceea0be72d3.zip |
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)
-rw-r--r-- | src/pl/plpython/plpy_exec.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 920322e912b..eb8441d9952 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -424,15 +424,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]; @@ -696,19 +701,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; - PG_TRY(); + /* + * 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) { - pltdata = PyDict_New(); - if (!pltdata) + pltargs = PyList_New(tdata->tg_trigger->tgnargs); + if (!pltargs) + { + Py_DECREF(pltdata); return NULL; + } + } + PG_TRY(); + { pltname = PyString_FromString(tdata->tg_trigger->tgname); PyDict_SetItemString(pltdata, "name", pltname); Py_DECREF(pltname); @@ -848,12 +868,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 = PyString_FromString(tdata->tg_trigger->tgargs[i]); @@ -874,6 +891,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r } PG_CATCH(); { + Py_XDECREF(pltargs); Py_XDECREF(pltdata); PG_RE_THROW(); } |