Hello, hackers.

I was investigating Valgrind issues with plpython. It turns out
python itself doesn't play well with Valgrind in default build.

Therefore I built python with valgrind related flags
        --with-valgrind --without-pymalloc
and added debug flags just to be sure
        --with-pydebug --with-assertions

It causes plpython's tests to fail on internal python's
assertions.
Example backtrace (python version 3.7, postgresql master branch):

#8  0x00007fbf02851662 in __GI___assert_fail "!PyErr_Occurred()"
        at assert.c:101
#9  0x00007fbef9060d31 in _PyType_Lookup
        at Objects/typeobject.c:3117                                            
                                     
#10 0x00007fbef90461be in _PyObject_GenericGetAttrWithDict
        at Objects/object.c:1231                                    
#11 0x00007fbef9046707 in PyObject_GenericGetAttr
        at Objects/object.c:1309                                                
                                     
#12 0x00007fbef9043cdf in PyObject_GetAttr
        at Objects/object.c:913
#13 0x00007fbef90458d9 in PyObject_GetAttrString
        at Objects/object.c:818
#14 0x00007fbf02499636 in get_string_attr
        at plpy_elog.c:569
#15 0x00007fbf02498ea5 in PLy_get_error_data
        at plpy_elog.c:420
#16 0x00007fbf0249763b in PLy_elog_impl
        at plpy_elog.c:77

Looks like there several places where code tries to get
attributes from error objects, and while code is ready for
attribute absence, it doesn't clear AttributeError exception
in that case.

Attached patch adds 3 calls to PyErr_Clear() in places where
code reacts on attribute absence. With this patch tests are
passed well.

There were similar findings before. Calls to PyErr_Clear were
close to, but not exactly at, same places before were removed
in
  7e3bb08038 Fix access-to-already-freed-memory issue in plpython's error 
handling.
Then one of PyErr_Clear were added in
  1d2f9de38d Fix freshly-introduced PL/Python portability bug.
But looks like there's need for more.

PS. When python is compilled `--with-valgrind --without-pymalloc`
Valgrind doesn't complain, so there are no memory related
issues in plpython.

regards

------

Yura Sokolov
y.sokolov
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index 7c627eacfbf..aa1cf17b366 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -359,7 +359,10 @@ PLy_get_sqlerrcode(PyObject *exc, int *sqlerrcode)
 
 	sqlstate = PyObject_GetAttrString(exc, "sqlstate");
 	if (sqlstate == NULL)
+	{
+		PyErr_Clear();
 		return;
+	}
 
 	buffer = PLyUnicode_AsString(sqlstate);
 	if (strlen(buffer) == 5 &&
@@ -395,6 +398,7 @@ PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail,
 	}
 	else
 	{
+		PyErr_Clear();
 		/*
 		 * If there's no spidata, at least set the sqlerrcode. This can happen
 		 * if someone explicitly raises a SPI exception from Python code.
@@ -571,6 +575,10 @@ get_string_attr(PyObject *obj, char *attrname, char **str)
 	{
 		*str = pstrdup(PLyUnicode_AsString(val));
 	}
+	else if (val == NULL)
+	{
+		PyErr_Clear();
+	}
 	Py_XDECREF(val);
 }
 

Reply via email to