From d0aa965c0a0ac2ff7906ae1b1dad50a7952efa56 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 31 Oct 2017 10:49:36 -0400 Subject: [PATCH] Consistently catch errors from Python _New() functions Python Py*_New() functions can fail and return NULL in out-of-memory conditions. The previous code handled that inconsistently or not at all. This change organizes that better. If we are in a function that is called from Python, we just check for failure and return NULL ourselves, which will cause any exception information to be passed up. If we are called from PostgreSQL, we consistently create an "out of memory" error. Reviewed-by: Tom Lane --- contrib/hstore_plpython/hstore_plpython.c | 4 ++++ contrib/ltree_plpython/ltree_plpython.c | 4 ++++ src/pl/plpython/plpy_cursorobject.c | 25 +++++++++++++-------- src/pl/plpython/plpy_exec.c | 10 ++++++++- src/pl/plpython/plpy_main.c | 2 +- src/pl/plpython/plpy_plpymodule.c | 4 ++-- src/pl/plpython/plpy_procedure.c | 2 ++ src/pl/plpython/plpy_resultobject.c | 11 +++++++++ src/pl/plpython/plpy_spi.c | 27 +++++++++++++++-------- src/pl/plpython/plpy_typeio.c | 4 +++- 10 files changed, 70 insertions(+), 23 deletions(-) diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c index 22366bd40f7..218e6612b14 100644 --- a/contrib/hstore_plpython/hstore_plpython.c +++ b/contrib/hstore_plpython/hstore_plpython.c @@ -93,6 +93,10 @@ hstore_to_plpython(PG_FUNCTION_ARGS) PyObject *dict; dict = PyDict_New(); + if (!dict) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); for (i = 0; i < count; i++) { diff --git a/contrib/ltree_plpython/ltree_plpython.c b/contrib/ltree_plpython/ltree_plpython.c index ae9b90dd10b..e88636a0a96 100644 --- a/contrib/ltree_plpython/ltree_plpython.c +++ b/contrib/ltree_plpython/ltree_plpython.c @@ -46,6 +46,10 @@ ltree_to_plpython(PG_FUNCTION_ARGS) ltree_level *curlevel; list = PyList_New(in->numlevel); + if (!list) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); curlevel = LTREE_FIRST(in); for (i = 0; i < in->numlevel; i++) diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c index 10ca786fbc2..9467f648082 100644 --- a/src/pl/plpython/plpy_cursorobject.c +++ b/src/pl/plpython/plpy_cursorobject.c @@ -457,17 +457,24 @@ PLy_cursor_fetch(PyObject *self, PyObject *args) Py_DECREF(ret->rows); ret->rows = PyList_New(SPI_processed); - - PLy_input_setup_tuple(&cursor->result, SPI_tuptable->tupdesc, - exec_ctx->curr_proc); - - for (i = 0; i < SPI_processed; i++) + if (!ret->rows) { - PyObject *row = PLy_input_from_tuple(&cursor->result, - SPI_tuptable->vals[i], - SPI_tuptable->tupdesc); + Py_DECREF(ret); + ret = NULL; + } + else + { + PLy_input_setup_tuple(&cursor->result, SPI_tuptable->tupdesc, + exec_ctx->curr_proc); - PyList_SetItem(ret->rows, i, row); + for (i = 0; i < SPI_processed; i++) + { + PyObject *row = PLy_input_from_tuple(&cursor->result, + SPI_tuptable->vals[i], + SPI_tuptable->tupdesc); + + PyList_SetItem(ret->rows, i, row); + } } } diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 02d7d2ad5f8..9d2341a4a3b 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -420,6 +420,9 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc) PG_TRY(); { args = PyList_New(proc->nargs); + if (!args) + return NULL; + for (i = 0; i < proc->nargs; i++) { PLyDatumToOb *arginfo = &proc->args[i]; @@ -693,7 +696,7 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r { pltdata = PyDict_New(); if (!pltdata) - PLy_elog(ERROR, "could not create new dictionary while building trigger arguments"); + return NULL; pltname = PyString_FromString(tdata->tg_trigger->tgname); PyDict_SetItemString(pltdata, "name", pltname); @@ -826,6 +829,11 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r PyObject *pltarg; pltargs = PyList_New(tdata->tg_trigger->tgnargs); + if (!pltargs) + { + Py_DECREF(pltdata); + return NULL; + } for (i = 0; i < tdata->tg_trigger->tgnargs; i++) { pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]); diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c index 29db90e4489..32d23ae5b6d 100644 --- a/src/pl/plpython/plpy_main.c +++ b/src/pl/plpython/plpy_main.c @@ -167,7 +167,7 @@ PLy_init_interp(void) PLy_interp_globals = PyModule_GetDict(mainmod); PLy_interp_safe_globals = PyDict_New(); if (PLy_interp_safe_globals == NULL) - PLy_elog(ERROR, "could not create globals"); + PLy_elog(ERROR, NULL); PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals); Py_DECREF(mainmod); if (PLy_interp_globals == NULL || PyErr_Occurred()) diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c index 759ad449323..23f99e20ca3 100644 --- a/src/pl/plpython/plpy_plpymodule.c +++ b/src/pl/plpython/plpy_plpymodule.c @@ -233,7 +233,7 @@ PLy_create_exception(char *name, PyObject *base, PyObject *dict, exc = PyErr_NewException(name, base, dict); if (exc == NULL) - PLy_elog(ERROR, "could not create exception \"%s\"", name); + PLy_elog(ERROR, NULL); /* * PyModule_AddObject does not add a refcount to the object, for some odd @@ -268,7 +268,7 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base) PyObject *dict = PyDict_New(); if (dict == NULL) - PLy_elog(ERROR, "could not generate SPI exceptions"); + PLy_elog(ERROR, NULL); sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate)); if (sqlstate == NULL) diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 58d69882025..faa4977463a 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -368,6 +368,8 @@ PLy_procedure_compile(PLyProcedure *proc, const char *src) * all functions */ proc->statics = PyDict_New(); + if (!proc->statics) + PLy_elog(ERROR, NULL); PyDict_SetItemString(proc->globals, "SD", proc->statics); /* diff --git a/src/pl/plpython/plpy_resultobject.c b/src/pl/plpython/plpy_resultobject.c index 098a366f6fa..ca70e256892 100644 --- a/src/pl/plpython/plpy_resultobject.c +++ b/src/pl/plpython/plpy_resultobject.c @@ -112,6 +112,11 @@ PLy_result_new(void) ob->nrows = PyInt_FromLong(-1); ob->rows = PyList_New(0); ob->tupdesc = NULL; + if (!ob->rows) + { + Py_DECREF(ob); + return NULL; + } return (PyObject *) ob; } @@ -147,6 +152,8 @@ PLy_result_colnames(PyObject *self, PyObject *unused) } list = PyList_New(ob->tupdesc->natts); + if (!list) + return NULL; for (i = 0; i < ob->tupdesc->natts; i++) { Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i); @@ -171,6 +178,8 @@ PLy_result_coltypes(PyObject *self, PyObject *unused) } list = PyList_New(ob->tupdesc->natts); + if (!list) + return NULL; for (i = 0; i < ob->tupdesc->natts; i++) { Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i); @@ -195,6 +204,8 @@ PLy_result_coltypmods(PyObject *self, PyObject *unused) } list = PyList_New(ob->tupdesc->natts); + if (!list) + return NULL; for (i = 0; i < ob->tupdesc->natts; i++) { Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i); diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index 69eb6b39f67..ade27f39242 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -360,6 +360,8 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) volatile MemoryContext oldcontext; result = (PLyResultObject *) PLy_result_new(); + if (!result) + return NULL; Py_DECREF(result->status); result->status = PyInt_FromLong(status); @@ -409,17 +411,24 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) Py_DECREF(result->rows); result->rows = PyList_New(rows); - - PLy_input_setup_tuple(&ininfo, tuptable->tupdesc, - exec_ctx->curr_proc); - - for (i = 0; i < rows; i++) + if (!result->rows) { - PyObject *row = PLy_input_from_tuple(&ininfo, - tuptable->vals[i], - tuptable->tupdesc); + Py_DECREF(result); + result = NULL; + } + else + { + PLy_input_setup_tuple(&ininfo, tuptable->tupdesc, + exec_ctx->curr_proc); - PyList_SetItem(result->rows, i, row); + for (i = 0; i < rows; i++) + { + PyObject *row = PLy_input_from_tuple(&ininfo, + tuptable->vals[i], + tuptable->tupdesc); + + PyList_SetItem(result->rows, i, row); + } } } diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c index ce1527072e4..c48e8fd5f3b 100644 --- a/src/pl/plpython/plpy_typeio.c +++ b/src/pl/plpython/plpy_typeio.c @@ -718,6 +718,8 @@ PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim, PyObject *list; list = PyList_New(dims[dim]); + if (!list) + return NULL; if (dim < ndim - 1) { @@ -826,7 +828,7 @@ PLyDict_FromTuple(PLyDatumToOb *arg, HeapTuple tuple, TupleDesc desc) dict = PyDict_New(); if (dict == NULL) - PLy_elog(ERROR, "could not create new dictionary"); + return NULL; PG_TRY(); {