From a9df45497dc79023ed1864dd9b8e435935220171 Mon Sep 17 00:00:00 2001
From: dnpwwo <kendel.boul@gmail.com>
Date: Tue, 1 Mar 2022 13:09:01 +1100
Subject: [PATCH] BugFix: Linux crash when formating Python exceptions Other: 
 Continue code cleanup

---
 hardware/plugins/Plugins.cpp | 45 +++++++++++-------------------------
 hardware/plugins/Plugins.h   |  3 ++-
 main/EventsPythonModule.cpp  |  6 ++---
 3 files changed, 18 insertions(+), 36 deletions(-)

--- a/hardware/plugins/Plugins.cpp
+++ b/hardware/plugins/Plugins.cpp
@@ -724,13 +724,7 @@ namespace Plugins
 		}
 		else
 		{
-			std::string	sTypeText("Unknown");
-			if (pExcept)
-			{
-				PyTypeObject* TypeName = (PyTypeObject*)pExcept;
-				PyNewRef	pName = PyObject_GetAttrString((PyObject*)TypeName, "__name__");
-				sTypeText = (std::string)pName;
-			}
+			std::string	sTypeText("Unknown Error");
 
 			/* See if we can get a full traceback */
 			PyNewRef	pModule = PyImport_ImportModule("traceback");
@@ -738,7 +732,7 @@ namespace Plugins
 			{
 				PyNewRef	pFunc = PyObject_GetAttrString(pModule, "format_exception");
 				if (pFunc && PyCallable_Check(pFunc)) {
-					PyNewRef	pList = PyObject_CallFunctionObjArgs(pFunc, pExcept, pValue, pTraceback, NULL);
+					PyNewRef	pList = PyObject_CallFunctionObjArgs(pFunc, (PyObject*)pExcept, (PyObject*)pValue, (PyObject*)pTraceback, NULL);
 					if (pList)
 					{
 						for (Py_ssize_t i = 0; i < PyList_Size(pList); i++)
@@ -756,16 +750,19 @@ namespace Plugins
 					}
 					else
 					{
+						if (pExcept) sTypeText = pExcept.Attribute("__name__");
 						Log(LOG_ERROR, "Exception: '%s'.  No traceback available.", sTypeText.c_str());
 					}
 				}
 				else
 				{
+					if (pExcept) sTypeText = pExcept.Attribute("__name__");
 					Log(LOG_ERROR, "'format_exception' lookup failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
 				}
 			}
 			else
 			{
+				if (pExcept) sTypeText = pExcept.Attribute("__name__");
 				Log(LOG_ERROR, "'Traceback' module import failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
 			}
 		}
@@ -1950,7 +1947,7 @@ namespace Plugins
 		}
 	}
 
-	void CPlugin::Callback(PyObject *pTarget, const std::string &sHandler, PyObject *pParams)
+	void CPlugin::Callback(PyBorrowedRef& pTarget, const std::string &sHandler, PyObject *pParams)
 	{
 		try
 		{
@@ -1966,19 +1963,8 @@ namespace Plugins
 				PyNewRef pFunc = PyObject_GetAttrString(pTarget, sHandler.c_str());
 				if (pFunc && PyCallable_Check(pFunc))
 				{
-					module_state *pModState = nullptr;
-					PyBorrowedRef brModule = PyState_FindModule(&DomoticzModuleDef);
-					if (!brModule)
-					{
-						brModule = PyState_FindModule(&DomoticzExModuleDef);
-					}
-
-					if (brModule)
-					{
-						pModState = ((struct module_state *)PyModule_GetState(brModule));
-					}
-
 					// Store the callback object so the Dump function has context if invoked
+					module_state* pModState = FindModule();
 					if (pModState)
 					{
 						pModState->lastCallback = pTarget;
@@ -1986,14 +1972,12 @@ namespace Plugins
 
 					if (m_bDebug & PDM_QUEUE)
 					{
-						PyNewRef	pName = PyObject_GetAttrString((PyObject*)(pTarget->ob_type), "__name__");
-						if (pName)
-							Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), (std::string(pName).c_str()));
+						Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), pTarget.Type().c_str());
 					}
 
 					PyErr_Clear();
 
-					// Invokde the callback function
+					// Invoke the callback function
 					PyNewRef	pReturnValue = PyObject_CallObject(pFunc, pParams);
 
 					if (pModState)
@@ -2020,17 +2004,14 @@ namespace Plugins
 									std::string sAttrName = pItem;
 									if (sAttrName.substr(0, 2) != "__") // ignore system stuff
 									{
-										if (PyObject_HasAttrString(pTarget, sAttrName.c_str()))
+										std::string	strValue = pTarget.Attribute(sAttrName);
+										if (strValue.length())
 										{
 											PyNewRef pValue = PyObject_GetAttrString(pTarget, sAttrName.c_str());
 											if (!PyCallable_Check(pValue)) // Filter out methods
 											{
-												std::string	strValue = pValue;
-												if (strValue.length())
-												{
-													std::string sBlank((sAttrName.length() < 20) ? 20 - sAttrName.length() : 0, ' ');
-													Log(LOG_NORM, " ----> '%s'%s '%s'", sAttrName.c_str(), sBlank.c_str(), strValue.c_str());
-												}
+												std::string sBlank((sAttrName.length() < 20) ? 20 - sAttrName.length() : 0, ' ');
+												Log(LOG_NORM, " ----> '%s'%s '%s'", sAttrName.c_str(), sBlank.c_str(), strValue.c_str());
 											}
 										}
 									}
--- a/hardware/plugins/Plugins.h
+++ b/hardware/plugins/Plugins.h
@@ -92,7 +92,7 @@ namespace Plugins {
 	  void ConnectionWrite(CDirectiveBase *);
 	  void ConnectionDisconnect(CDirectiveBase *);
 	  void DisconnectEvent(CEventBase *);
-	  void Callback(PyObject* pTarget, const std::string &sHandler, PyObject *pParams);
+	  void Callback(PyBorrowedRef& pTarget, const std::string &sHandler, PyObject *pParams);
 	  void RestoreThread();
 	  void ReleaseThread();
 	  void Stop();
@@ -157,6 +157,7 @@ namespace Plugins {
 			m_pObject = pObject;
 		};
 		std::string	Attribute(const char* name);
+		std::string	Attribute(std::string& name) { return Attribute(name.c_str()); };
 		std::string	Type();
 		bool		IsDict() { return TypeCheck(Py_TPFLAGS_DICT_SUBCLASS); };
 		bool		IsList() { return TypeCheck(Py_TPFLAGS_LIST_SUBCLASS); };
--- a/main/EventsPythonModule.cpp
+++ b/main/EventsPythonModule.cpp
@@ -297,7 +297,7 @@ namespace Plugins
 			PyBorrowedRef	pModule = PythonEventsGetModule();
 			if (pModule)
 			{
-				PyBorrowedRef	pModuleDict = Plugins::PyModule_GetDict(pModule);
+				PyBorrowedRef	pModuleDict = PyModule_GetDict(pModule);
 				if (!pModuleDict)
 				{
 					_log.Log(LOG_ERROR, "Python EventSystem: Failed to open module dictionary.");
@@ -312,7 +312,7 @@ namespace Plugins
 					return;
 				}
 
-				PyNewRef	pDeviceDict = Plugins::PyDict_New();
+				PyNewRef	pDeviceDict = PyDict_New();
 				if (PyDict_SetItemString(pModuleDict, "Devices", pDeviceDict) == -1)
 				{
 					_log.Log(LOG_ERROR, "Python EventSystem: Failed to add Device dictionary.");
@@ -320,7 +320,7 @@ namespace Plugins
 					return;
 				}
 
-				if (PyType_Ready((PyTypeObject*)Plugins::PDeviceType) < 0)
+				if (PyType_Ready((PyTypeObject*)PDeviceType) < 0)
 				{
 					_log.Log(LOG_ERROR, "Python EventSystem: Unable to ready DeviceType Object.");
 					PyEval_SaveThread();
