[Lldb-commits] [lldb] r252536 - Use PythonDataObjects in swig helper functions.

Zachary Turner via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 9 15:23:52 PST 2015


Author: zturner
Date: Mon Nov  9 17:23:52 2015
New Revision: 252536

URL: http://llvm.org/viewvc/llvm-project?rev=252536&view=rev
Log:
Use PythonDataObjects in swig helper functions.

Relying on manual Python C API calls is error prone, especially
when trying to maintain compatibility with Python 2 and Python 3.

This patch additionally fixes what appears to be a potentially
serious memory leak, in that were were incref'ing two values
returned from the session dictionary but never decref'ing them.
There was a comment indicating that it was intentional, but the
reasoning was, I believe, faulty and it resulted in a legitimate
memory leak.

Switching everything to PythonObject based classes solves both
the compatibility issues as well as the resource leak issues.

Modified:
    lldb/trunk/scripts/Python/python-wrapper.swig

Modified: lldb/trunk/scripts/Python/python-wrapper.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-wrapper.swig?rev=252536&r1=252535&r2=252536&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-wrapper.swig (original)
+++ lldb/trunk/scripts/Python/python-wrapper.swig Mon Nov  9 17:23:52 2015
@@ -26,72 +26,70 @@ private:
     bool m_print;
 };
 
+// TODO(zturner): This should be part of a `PythonModule` class in
+// PythonDataObjects.hm and it should return a `PythonObject`
 static PyObject*
 ResolvePythonName(const char* name,
                   PyObject* pmodule)
 {
+    using namespace lldb_private;
     if (!name)
         return pmodule;
 
     PyErr_Cleaner pyerr_cleanup(true);  // show Python errors
 
-    PyObject* main_dict;
+    PythonDictionary main_dict(PyInitialValue::Invalid);
 
     if (!pmodule)
     {
         pmodule = PyImport_AddModule ("__main__");
         if (!pmodule)
-            return NULL;
+            return nullptr;
     }
 
     if (PyType_Check(pmodule))
-    {
-        main_dict = ((PyTypeObject*)pmodule)->tp_dict;
-        if (!main_dict)
-            return NULL;
-    }
-    else if (!PyDict_Check(pmodule))
-    {
-        main_dict = PyModule_GetDict (pmodule);
-        if (!main_dict)
-            return NULL;
-    }
+        main_dict.Reset(PyRefType::Borrowed, ((PyTypeObject*)pmodule)->tp_dict);
+    else if (PythonDictionary::Check(pmodule))
+        main_dict.Reset(PyRefType::Borrowed, pmodule);
     else
-        main_dict = pmodule;
+        main_dict.Reset(PyRefType::Borrowed, PyModule_GetDict (pmodule));
+    if (!main_dict.IsValid())
+        return nullptr;
 
     const char* dot_pos = ::strchr(name, '.');
 
-    PyObject *dest_object;
-    PyObject *key, *value;
+    PythonObject dest_object;
     Py_ssize_t pos = 0;
 
     if (!dot_pos)
     {
-        dest_object = NULL;
-        while (PyDict_Next (main_dict, &pos, &key, &value))
+        PyObject *py_key;
+        PyObject *py_value;
+        // TODO(zturner): This should be conveniently wrapped by `PythonDictionary`.
+        while (PyDict_Next(main_dict.get(), &pos, &py_key, &py_value))
         {
-            // We have stolen references to the key and value objects in the dictionary; we need to increment
-            // them now so that Python's garbage collector doesn't collect them out from under us.
-            Py_INCREF (key);
-            Py_INCREF (value);
-            if (strcmp (PyString_AsString (key), name) == 0)
+            PythonObject key(PyRefType::Borrowed, py_key);
+            auto key_string = key.AsType<PythonString>();
+            if (!key_string.IsAllocated())
+                continue;
+
+            std::string str(key_string.GetString().str());
+            if (strcmp(str.c_str(), name) == 0)
             {
-                dest_object = value;
+                dest_object.Reset(PyRefType::Borrowed, py_value);
                 break;
             }
         }
-        if (!dest_object || dest_object == Py_None)
-            return NULL;
-        return dest_object;
+        return dest_object.release();
     }
     else
     {
         size_t len = dot_pos - name;
         std::string piece(name,len);
-        pmodule = ResolvePythonName(piece.c_str(), main_dict);
-        if (!pmodule)
-            return NULL;
-        return ResolvePythonName(dot_pos+1,pmodule); // tail recursion.. should be optimized by the compiler
+        PyObject *resolved_object = ResolvePythonName(piece.c_str(), main_dict.get());
+        if (!resolved_object || resolved_object == Py_None)
+            return nullptr;
+        return ResolvePythonName(dot_pos+1,resolved_object); // tail recursion.. should be optimized by the compiler
     }
 }
 
@@ -101,6 +99,8 @@ FindSessionDictionary(const char *sessio
     return ResolvePythonName(session_dictionary_name, NULL);
 }
 
+// TODO(zturner): This entire class should be moved to PythonDataObjects.h
+// and properly abstracted and unit-tested.
 class PyCallable
 {
 public:




More information about the lldb-commits mailing list