From 5cd72c7a7c7bd76ab028e1dc59d90a47750acebe Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 13 Mar 2012 15:26:32 -0400
Subject: [PATCH] Patch some corner-case bugs in pl/python.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Dave Malcolm of Red Hat is working on a static code analysis tool for
Python-related C code.  It reported a number of problems in plpython,
most of which were failures to check for NULL results from object-creation
functions, so would only be an issue in very-low-memory situations.

Patch in HEAD and 9.1.  We could go further back but it's not clear that
these issues are important enough to justify the work.

Jan Urbański
---
 src/pl/plpython/plpy_elog.c       |  4 ++++
 src/pl/plpython/plpy_main.c       |  2 ++
 src/pl/plpython/plpy_plpymodule.c | 18 ++++++++++++++++--
 src/pl/plpython/plpy_spi.c        |  3 ++-
 src/pl/plpython/plpy_typeio.c     |  2 ++
 5 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index 2f04a8c0dba..f7d321289d4 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -367,6 +367,10 @@ get_source_line(const char *src, int lineno)
 	const char *next = src;
 	int			current = 0;
 
+	/* sanity check */
+	if (lineno <= 0)
+		return NULL;
+
 	while (current < lineno)
 	{
 		s = next;
diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
index 277dedc22d2..c126db995ae 100644
--- a/src/pl/plpython/plpy_main.c
+++ b/src/pl/plpython/plpy_main.c
@@ -142,6 +142,8 @@ PLy_init_interp(void)
 	Py_INCREF(mainmod);
 	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");
 	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 d2d0a2a2323..01caa0a3236 100644
--- a/src/pl/plpython/plpy_plpymodule.c
+++ b/src/pl/plpython/plpy_plpymodule.c
@@ -173,9 +173,11 @@ PLy_init_plpy(void)
 	main_mod = PyImport_AddModule("__main__");
 	main_dict = PyModule_GetDict(main_mod);
 	plpy_mod = PyImport_AddModule("plpy");
+	if (plpy_mod == NULL)
+		PLy_elog(ERROR, "could not initialize plpy");
 	PyDict_SetItemString(main_dict, "plpy", plpy_mod);
 	if (PyErr_Occurred())
-		elog(ERROR, "could not initialize plpy");
+		PLy_elog(ERROR, "could not initialize plpy");
 }
 
 static void
@@ -208,6 +210,11 @@ PLy_add_exceptions(PyObject *plpy)
 	PLy_exc_fatal = PyErr_NewException("plpy.Fatal", NULL, NULL);
 	PLy_exc_spi_error = PyErr_NewException("plpy.SPIError", NULL, NULL);
 
+	if (PLy_exc_error == NULL ||
+		PLy_exc_fatal == NULL ||
+		PLy_exc_spi_error == NULL)
+		PLy_elog(ERROR, "could not create the base SPI exceptions");
+
 	Py_INCREF(PLy_exc_error);
 	PyModule_AddObject(plpy, "Error", PLy_exc_error);
 	Py_INCREF(PLy_exc_fatal);
@@ -241,7 +248,13 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base)
 		PyObject   *sqlstate;
 		PyObject   *dict = PyDict_New();
 
+		if (dict == NULL)
+			PLy_elog(ERROR, "could not generate SPI exceptions");
+
 		sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate));
+		if (sqlstate == NULL)
+			PLy_elog(ERROR, "could not generate SPI exceptions");
+
 		PyDict_SetItemString(dict, "sqlstate", sqlstate);
 		Py_DECREF(sqlstate);
 		exc = PyErr_NewException(exception_map[i].name, base, dict);
@@ -370,7 +383,8 @@ PLy_output(volatile int level, PyObject *self, PyObject *args)
 		 */
 		PyObject   *o;
 
-		PyArg_UnpackTuple(args, "plpy.elog", 1, 1, &o);
+		if (!PyArg_UnpackTuple(args, "plpy.elog", 1, 1, &o))
+			PLy_elog(ERROR, "could not unpack arguments in plpy.elog");
 		so = PyObject_Str(o);
 	}
 	else
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index a75839b93ea..cde3c08f967 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -340,7 +340,7 @@ PLy_spi_execute_query(char *query, long limit)
 	int			rv;
 	volatile MemoryContext oldcontext;
 	volatile ResourceOwner oldowner;
-	PyObject   *ret;
+	PyObject   *ret = NULL;
 
 	oldcontext = CurrentMemoryContext;
 	oldowner = CurrentResourceOwner;
@@ -366,6 +366,7 @@ PLy_spi_execute_query(char *query, long limit)
 
 	if (rv < 0)
 	{
+		Py_XDECREF(ret);
 		PLy_exception_set(PLy_exc_spi_error,
 						  "SPI_execute failed: %s",
 						  SPI_result_code_string(rv));
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index d04fe46d4b7..9d6af053761 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -584,6 +584,8 @@ PLyList_FromArray(PLyDatumToOb *arg, Datum d)
 	length = ARR_DIMS(array)[0];
 	lbound = ARR_LBOUND(array)[0];
 	list = PyList_New(length);
+	if (list == NULL)
+		PLy_elog(ERROR, "could not create new Python list");
 
 	for (i = 0; i < length; i++)
 	{
-- 
GitLab