peltool: Fix Python C Extension for UD parsing
This fixes some issues with reference counting which could possibly
lead to memory leaks and unwanted behaviours.
Only accepts valid data from python module (non-empty object, array and
string) or else to return the default hex dump.
Signed-off-by: Harisuddin Mohamed Isa <harisuddin@gmail.com>
Change-Id: I13d06247533018709b93e5d7887453e652132956
diff --git a/extensions/openpower-pels/user_data_json.cpp b/extensions/openpower-pels/user_data_json.cpp
index 791c39c..9d331a3 100644
--- a/extensions/openpower-pels/user_data_json.cpp
+++ b/extensions/openpower-pels/user_data_json.cpp
@@ -255,7 +255,7 @@
uint8_t creatorID)
{
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pData, *pResult,
- *pBytes, *eType, *eValue, *eTraceback;
+ *pBytes, *eType, *eValue, *eTraceback, *pKey;
std::string pErrStr;
std::string module = getNumberString("%c", tolower(creatorID)) +
getNumberString("%04x", componentID);
@@ -263,25 +263,53 @@
std::string("udparsers." + module + "." + module).c_str());
std::unique_ptr<PyObject, decltype(&pyDecRef)> modNamePtr(pName, &pyDecRef);
pModule = PyImport_Import(pName);
- std::unique_ptr<PyObject, decltype(&pyDecRef)> modPtr(pModule, &pyDecRef);
if (pModule == NULL)
{
pErrStr = "No error string found";
PyErr_Fetch(&eType, &eValue, &eTraceback);
+ if (eType)
+ {
+ Py_XDECREF(eType);
+ }
+ if (eTraceback)
+ {
+ Py_XDECREF(eTraceback);
+ }
if (eValue)
{
PyObject* pStr = PyObject_Str(eValue);
+ Py_XDECREF(eValue);
if (pStr)
{
pErrStr = PyUnicode_AsUTF8(pStr);
+ Py_XDECREF(pStr);
}
- Py_XDECREF(pStr);
}
}
else
{
+ std::unique_ptr<PyObject, decltype(&pyDecRef)> modPtr(pModule,
+ &pyDecRef);
+ std::string funcToCall = "parseUDToJson";
+ pKey = PyUnicode_FromString(funcToCall.c_str());
+ std::unique_ptr<PyObject, decltype(&pyDecRef)> keyPtr(pKey, &pyDecRef);
pDict = PyModule_GetDict(pModule);
- pFunc = PyDict_GetItemString(pDict, "parseUDToJson");
+ Py_INCREF(pDict);
+ if (!PyDict_Contains(pDict, pKey))
+ {
+ Py_DECREF(pDict);
+ log<level::ERR>(
+ "Python module error",
+ entry("ERROR=%s",
+ std::string(funcToCall + " function missing").c_str()),
+ entry("PARSER_MODULE=%s", module.c_str()),
+ entry("SUBTYPE=0x%X", subType), entry("VERSION=%d", version),
+ entry("DATA_LENGTH=%lu\n", data.size()));
+ return std::nullopt;
+ }
+ pFunc = PyDict_GetItemString(pDict, funcToCall.c_str());
+ Py_DECREF(pDict);
+ Py_INCREF(pFunc);
if (PyCallable_Check(pFunc))
{
auto ud = data.data();
@@ -295,14 +323,13 @@
pData = PyMemoryView_FromMemory(
reinterpret_cast<char*>(const_cast<unsigned char*>(ud)),
data.size(), PyBUF_READ);
- std::unique_ptr<PyObject, decltype(&pyDecRef)> dataPtr(pData,
- &pyDecRef);
PyTuple_SetItem(pArgs, 2, pData);
pResult = PyObject_CallObject(pFunc, pArgs);
- std::unique_ptr<PyObject, decltype(&pyDecRef)> resPtr(pResult,
- &pyDecRef);
+ Py_DECREF(pFunc);
if (pResult)
{
+ std::unique_ptr<PyObject, decltype(&pyDecRef)> resPtr(
+ pResult, &pyDecRef);
pBytes = PyUnicode_AsEncodedString(pResult, "utf-8", "~E~");
std::unique_ptr<PyObject, decltype(&pyDecRef)> pyBytePtr(
pBytes, &pyDecRef);
@@ -310,7 +337,12 @@
try
{
orderedJSON json = orderedJSON::parse(output);
- return prettyJSON(componentID, subType, version, json);
+ if ((json.is_object() && !json.empty()) ||
+ (json.is_array() && json.size() > 0) ||
+ (json.is_string() && json != ""))
+ {
+ return prettyJSON(componentID, subType, version, json);
+ }
}
catch (std::exception& e)
{
@@ -327,14 +359,23 @@
{
pErrStr = "No error string found";
PyErr_Fetch(&eType, &eValue, &eTraceback);
+ if (eType)
+ {
+ Py_XDECREF(eType);
+ }
+ if (eTraceback)
+ {
+ Py_XDECREF(eTraceback);
+ }
if (eValue)
{
PyObject* pStr = PyObject_Str(eValue);
+ Py_XDECREF(eValue);
if (pStr)
{
pErrStr = PyUnicode_AsUTF8(pStr);
+ Py_XDECREF(pStr);
}
- Py_XDECREF(pStr);
}
}
}
@@ -348,9 +389,6 @@
entry("VERSION=%d", version),
entry("DATA_LENGTH=%lu\n", data.size()));
}
- Py_XDECREF(eType);
- Py_XDECREF(eValue);
- Py_XDECREF(eTraceback);
return std::nullopt;
}