From eca2709cd1654e2fc37b75fa3bdfe5e199c86cb9 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. --- contrib/hstore_plpython/hstore_plpython.c | 4 ++++ contrib/ltree_plpython/ltree_plpython.c | 4 ++++ src/pl/plpython/plpy_cursorobject.c | 19 ++++++++++++------- src/pl/plpython/plpy_exec.c | 10 +++++++++- src/pl/plpython/plpy_main.c | 2 +- src/pl/plpython/plpy_plpymodule.c | 6 ++++-- src/pl/plpython/plpy_procedure.c | 2 ++ src/pl/plpython/plpy_resultobject.c | 11 +++++++++++ src/pl/plpython/plpy_spi.c | 25 +++++++++++++++++-------- src/pl/plpython/plpy_typeio.c | 4 +++- 10 files changed, 67 insertions(+), 20 deletions(-) diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c index 22366bd40f..218e6612b1 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 ae9b90dd10..e88636a0a9 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 0108471bfe..4af7c6621f 100644 --- a/src/pl/plpython/plpy_cursorobject.c +++ b/src/pl/plpython/plpy_cursorobject.c @@ -464,15 +464,20 @@ PLy_cursor_fetch(PyObject *self, PyObject *args) Py_DECREF(ret->rows); ret->rows = PyList_New(SPI_processed); - - for (i = 0; i < SPI_processed; i++) + if (!ret->rows) { - PyObject *row = PLyDict_FromTuple(&cursor->result, - SPI_tuptable->vals[i], - SPI_tuptable->tupdesc); - - PyList_SetItem(ret->rows, i, row); + Py_DECREF(ret); + ret = NULL; } + else + for (i = 0; i < SPI_processed; i++) + { + PyObject *row = PLyDict_FromTuple(&cursor->result, + SPI_tuptable->vals[i], + SPI_tuptable->tupdesc); + + PyList_SetItem(ret->rows, i, row); + } } SPI_freetuptable(SPI_tuptable); diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 26f61dd0f3..7cfa146c82 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -434,6 +434,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++) { if (proc->args[i].is_rowtype > 0) @@ -740,7 +743,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); @@ -869,6 +872,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 7df50c09c8..12f61b7ab2 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 759ad44932..08b0efb158 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); + return 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) @@ -279,6 +279,8 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base) exc = PLy_create_exception(exception_map[i].name, base, dict, exception_map[i].classname, mod); + if (!exc) + PLy_elog(ERROR, "could not create exception \"%s\"", exception_map[i].name); entry = hash_search(PLy_spi_exceptions, &exception_map[i].sqlstate, HASH_ENTER, &found); diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 26acc88b27..022bc00293 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -379,6 +379,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 098a366f6f..ca70e25689 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 955769c5e3..cad1324205 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -389,6 +389,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); @@ -435,15 +437,22 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) Py_DECREF(result->rows); result->rows = PyList_New(rows); - - PLy_input_tuple_funcs(&args, tuptable->tupdesc); - for (i = 0; i < rows; i++) + if (!result->rows) { - PyObject *row = PLyDict_FromTuple(&args, - tuptable->vals[i], - tuptable->tupdesc); - - PyList_SetItem(result->rows, i, row); + Py_DECREF(result); + result = NULL; + } + else + { + PLy_input_tuple_funcs(&args, tuptable->tupdesc); + for (i = 0; i < rows; i++) + { + PyObject *row = PLyDict_FromTuple(&args, + 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 e4af8cc9ef..569eb5862e 100644 --- a/src/pl/plpython/plpy_typeio.c +++ b/src/pl/plpython/plpy_typeio.c @@ -289,7 +289,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) dict = PyDict_New(); if (dict == NULL) - PLy_elog(ERROR, "could not create new dictionary"); + return NULL; PG_TRY(); { @@ -675,6 +675,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) { -- 2.14.3