peltool: Fixed output for SRC parser

This changes the output of SRC parser when empty JSON object or array is
returned by python module. No "SRC Details" key will be shown.

JSON objects will also be nested under "SRC Details" instead of
appending to the "Primary SRC" key:

    "Hex Word 8":               "00000000",
    "Hex Word 9":               "00000000",
    "SRC Details": {
        "Key": "Value"
    }

Fixed reference counting to avoid possible memory leaks and undefined behaviours.

Signed-off-by: Harisuddin Mohamed Isa <harisuddin@gmail.com>
Change-Id: I4bf5382ee9eac53f38b8e1cf7ead8a9d2dd47f8d
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
index 7ac9e93..9c0c3dd 100644
--- a/extensions/openpower-pels/src.cpp
+++ b/extensions/openpower-pels/src.cpp
@@ -70,7 +70,7 @@
     {
         for (const auto& [key, value] : json.items())
         {
-            output[key] = value;
+            output["SRC Details"][key] = value;
         }
     }
 
@@ -127,32 +127,59 @@
                                          uint8_t creatorID)
 {
     PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pResult, *pBytes,
-        *eType, *eValue, *eTraceback;
+        *eType, *eValue, *eTraceback, *pKey;
     std::string pErrStr;
     std::string module = getNumberString("%c", tolower(creatorID)) + "src";
     pName = PyUnicode_FromString(
         std::string("srcparsers." + 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 = "parseSRCToJson";
+        pKey = PyUnicode_FromString(funcToCall.c_str());
+        std::unique_ptr<PyObject, decltype(&pyDecRef)> keyPtr(pKey, &pyDecRef);
         pDict = PyModule_GetDict(pModule);
-        pFunc = PyDict_GetItemString(pDict, "parseSRCToJson");
+        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("SRC=%s", hexwords.front().c_str()),
+                entry("PARSER_MODULE=%s", module.c_str()));
+            return std::nullopt;
+        }
+        pFunc = PyDict_GetItemString(pDict, funcToCall.c_str());
+        Py_DECREF(pDict);
+        Py_INCREF(pFunc);
         if (PyCallable_Check(pFunc))
         {
             pArgs = PyTuple_New(9);
@@ -172,10 +199,11 @@
                 }
             }
             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);
@@ -183,7 +211,12 @@
                 try
                 {
                     orderedJSON json = orderedJSON::parse(output);
-                    return prettyJSON(json);
+                    if ((json.is_object() && !json.empty()) ||
+                        (json.is_array() && json.size() > 0) ||
+                        (json.is_string() && json != ""))
+                    {
+                        return prettyJSON(json);
+                    }
                 }
                 catch (std::exception& e)
                 {
@@ -198,14 +231,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);
                 }
             }
         }
@@ -217,9 +259,6 @@
                         entry("SRC=%s", hexwords.front().c_str()),
                         entry("PARSER_MODULE=%s", module.c_str()));
     }
-    Py_XDECREF(eType);
-    Py_XDECREF(eValue);
-    Py_XDECREF(eTraceback);
     return std::nullopt;
 }
 #endif