[Lldb-commits] [lldb] r250195 - Fix ref counting of Python objects.

Zachary Turner via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 13 11:16:15 PDT 2015


Author: zturner
Date: Tue Oct 13 13:16:15 2015
New Revision: 250195

URL: http://llvm.org/viewvc/llvm-project?rev=250195&view=rev
Log:
Fix ref counting of Python objects.

PythonObjects were being incorrectly ref-counted. This problem was
pervasive throughout the codebase, leading to an unknown number of memory
leaks and potentially use-after-free.

The issue stems from the fact that Python native methods can either return
"borrowed" references or "owned" references. For the former category, you
*must* incref it prior to decrefing it. And for the latter category, you
should not incref it before decrefing it. This is mostly an issue when a
Python C API method returns a `PyObject` to you, but it can also happen with
a method accepts a `PyObject`. Notably, this happens in `PyList_SetItem`,
which is documented to "steal" the reference that you give it. So if you
pass something to `PyList_SetItem`, you cannot hold onto it unless you
incref it first. But since this is one of only two exceptions in the
entire API, it's confusing and difficult to remember.

Our `PythonObject` class was indiscriminantely increfing every object it
received, which means that if you passed it an owned reference, you now
have a dangling reference since owned references should not be increfed.
We were doing this in quite a few places.

There was also a fair amount of manual increfing and decrefing prevalent
throughout the codebase, which is easy to get wrong.

This patch solves the problem by making any construction of a
`PythonObject` from a `PyObject` take a flag which indicates whether it is
an owned reference or a borrowed reference. There is no way to construct a
`PythonObject` without this flag, and it does not offer a default value,
forcing the user to make an explicit decision every time.

All manual uses of `PyObject` have been cleaned up throughout the codebase
and replaced with `PythonObject` in order to make RAII the predominant
pattern when dealing with native Python objects.

Differential Revision: http://reviews.llvm.org/D13617
Reviewed By: Greg Clayton

Modified:
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
    lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp?rev=250195&r1=250194&r2=250195&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp Tue Oct 13 13:16:15 2015
@@ -37,7 +37,7 @@ StructuredPythonObject::Dump(Stream &s)
 //----------------------------------------------------------------------
 
 void
-PythonObject::Dump (Stream &strm) const
+PythonObject::Dump(Stream &strm) const
 {
     if (m_py_obj)
     {
@@ -64,7 +64,7 @@ PythonObject::Dump (Stream &strm) const
 PyObjectType
 PythonObject::GetObjectType() const
 {
-    if (IsNULLOrNone())
+    if (!IsAllocated())
         return PyObjectType::None;
 
     if (PyList_Check(m_py_obj))
@@ -87,31 +87,43 @@ PythonObject::GetObjectType() const
 }
 
 PythonString
-PythonObject::Repr ()
+PythonObject::Repr()
 {
     if (!m_py_obj)
-        return PythonString ();
+        return PythonString();
     PyObject *repr = PyObject_Repr(m_py_obj);
     if (!repr)
-        return PythonString ();
-    return PythonString(repr);
+        return PythonString();
+    return PythonString(PyRefType::Owned, repr);
 }
 
 PythonString
-PythonObject::Str ()
+PythonObject::Str()
 {
     if (!m_py_obj)
-        return PythonString ();
+        return PythonString();
     PyObject *str = PyObject_Str(m_py_obj);
     if (!str)
-        return PythonString ();
-    return PythonString(str);
+        return PythonString();
+    return PythonString(PyRefType::Owned, str);
 }
 
 bool
-PythonObject::IsNULLOrNone () const
+PythonObject::IsNone() const
 {
-    return ((m_py_obj == nullptr) || (m_py_obj == Py_None));
+    return m_py_obj == Py_None;
+}
+
+bool
+PythonObject::IsValid() const
+{
+    return m_py_obj != nullptr;
+}
+
+bool
+PythonObject::IsAllocated() const
+{
+    return IsValid() && !IsNone();
 }
 
 StructuredData::ObjectSP
@@ -120,13 +132,13 @@ PythonObject::CreateStructuredObject() c
     switch (GetObjectType())
     {
         case PyObjectType::Dictionary:
-            return PythonDictionary(m_py_obj).CreateStructuredDictionary();
+            return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary();
         case PyObjectType::Integer:
-            return PythonInteger(m_py_obj).CreateStructuredInteger();
+            return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger();
         case PyObjectType::List:
-            return PythonList(m_py_obj).CreateStructuredArray();
+            return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
         case PyObjectType::String:
-            return PythonString(m_py_obj).CreateStructuredString();
+            return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
         case PyObjectType::None:
             return StructuredData::ObjectSP();
         default:
@@ -138,16 +150,15 @@ PythonObject::CreateStructuredObject() c
 // PythonString
 //----------------------------------------------------------------------
 
-PythonString::PythonString (PyObject *py_obj) :
-    PythonObject()
+PythonString::PythonString(PyRefType type, PyObject *py_obj)
+    : PythonObject()
 {
-    Reset(py_obj); // Use "Reset()" to ensure that py_obj is a string
+    Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
 }
 
-PythonString::PythonString (const PythonObject &object) :
-    PythonObject()
+PythonString::PythonString(const PythonString &object)
+    : PythonObject(object)
 {
-    Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string
 }
 
 PythonString::PythonString(llvm::StringRef string)
@@ -162,8 +173,8 @@ PythonString::PythonString(const char *s
     SetString(llvm::StringRef(string));
 }
 
-PythonString::PythonString () :
-    PythonObject()
+PythonString::PythonString()
+    : PythonObject()
 {
 }
 
@@ -184,35 +195,40 @@ PythonString::Check(PyObject *py_obj)
 #endif
 }
 
-bool
-PythonString::Reset(PyObject *py_obj)
+void
+PythonString::Reset(PyRefType type, PyObject *py_obj)
 {
+    // Grab the desired reference type so that if we end up rejecting
+    // `py_obj` it still gets decremented if necessary.
+    PythonObject result(type, py_obj);
+
     if (!PythonString::Check(py_obj))
     {
-        PythonObject::Reset(nullptr);
-        return false;
+        PythonObject::Reset();
+        return;
     }
 
-// Convert this to a PyBytes object, and only store the PyBytes.  Note that in
-// Python 2.x, PyString and PyUnicode are interchangeable, and PyBytes is an alias
-// of PyString.  So on 2.x, if we get into this branch, we already have a PyBytes.
-    //#if PY_MAJOR_VERSION >= 3
+    // Convert this to a PyBytes object, and only store the PyBytes.  Note that in
+    // Python 2.x, PyString and PyUnicode are interchangeable, and PyBytes is an alias
+    // of PyString.  So on 2.x, if we get into this branch, we already have a PyBytes.
     if (PyUnicode_Check(py_obj))
     {
-        PyObject *unicode = py_obj;
-        py_obj = PyUnicode_AsUTF8String(py_obj);
-        Py_XDECREF(unicode);
+        // Since we're converting this to a different object, we assume ownership of the
+        // new object regardless of the value of `type`.
+        result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(py_obj));
     }
-    //#endif
 
-    assert(PyBytes_Check(py_obj) && "PythonString::Reset received a non-string");
-    return PythonObject::Reset(py_obj);
+    assert(PyBytes_Check(result.get()) && "PythonString::Reset received a non-string");
+
+    // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
+    // back into the virtual implementation.
+    PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 llvm::StringRef
 PythonString::GetString() const
 {
-    if (m_py_obj)
+    if (IsValid())
     {
         Py_ssize_t size;
         char *c;
@@ -225,7 +241,7 @@ PythonString::GetString() const
 size_t
 PythonString::GetSize() const
 {
-    if (m_py_obj)
+    if (IsValid())
         return PyBytes_Size(m_py_obj);
     return 0;
 }
@@ -236,10 +252,10 @@ PythonString::SetString (llvm::StringRef
 #if PY_MAJOR_VERSION >= 3
     PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
     PyObject *bytes = PyUnicode_AsUTF8String(unicode);
-    PythonObject::Reset(bytes);
-    Py_XDECREF(unicode);
+    PythonObject::Reset(PyRefType::Owned, bytes);
+    Py_DECREF(unicode);
 #else
-    PythonObject::Reset(PyString_FromStringAndSize(string.data(), string.size()));
+    PythonObject::Reset(PyRefType::Owned, PyString_FromStringAndSize(string.data(), string.size()));
 #endif
 }
 
@@ -255,22 +271,21 @@ PythonString::CreateStructuredString() c
 // PythonInteger
 //----------------------------------------------------------------------
 
-PythonInteger::PythonInteger (PyObject *py_obj) :
-    PythonObject()
+PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
+    : PythonObject()
 {
-    Reset(py_obj); // Use "Reset()" to ensure that py_obj is a integer type
+    Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
 }
 
-PythonInteger::PythonInteger (const PythonObject &object) :
-    PythonObject()
+PythonInteger::PythonInteger(const PythonInteger &object)
+    : PythonObject(object)
 {
-    Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type
 }
 
-PythonInteger::PythonInteger (int64_t value) :
-    PythonObject()
+PythonInteger::PythonInteger(int64_t value)
+    : PythonObject()
 {
-    SetInteger (value);
+    SetInteger(value);
 }
 
 
@@ -293,13 +308,17 @@ PythonInteger::Check(PyObject *py_obj)
 #endif
 }
 
-bool
-PythonInteger::Reset(PyObject *py_obj)
+void
+PythonInteger::Reset(PyRefType type, PyObject *py_obj)
 {
+    // Grab the desired reference type so that if we end up rejecting
+    // `py_obj` it still gets decremented if necessary.
+    PythonObject result(type, py_obj);
+
     if (!PythonInteger::Check(py_obj))
     {
-        PythonObject::Reset(nullptr);
-        return false;
+        PythonObject::Reset();
+        return;
     }
 
 #if PY_MAJOR_VERSION < 3
@@ -308,15 +327,18 @@ PythonInteger::Reset(PyObject *py_obj)
     // since 3.x doesn't even have a PyInt.
     if (PyInt_Check(py_obj))
     {
-        PyObject *py_long = PyLong_FromLongLong(PyInt_AsLong(py_obj));
-        Py_XDECREF(py_obj);
-        py_obj = py_long;
+        // Since we converted the original object to a different type, the new
+        // object is an owned object regardless of the ownership semantics requested
+        // by the user.
+        result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
     }
 #endif
 
-    assert(PyLong_Check(py_obj) && "Couldn't get a PyLong from this PyObject");
+    assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject");
 
-    return PythonObject::Reset(py_obj);
+    // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
+    // back into the virtual implementation.
+    PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 int64_t
@@ -332,9 +354,9 @@ PythonInteger::GetInteger() const
 }
 
 void
-PythonInteger::SetInteger (int64_t value)
+PythonInteger::SetInteger(int64_t value)
 {
-    PythonObject::Reset(PyLong_FromLongLong(value));
+    PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value));
 }
 
 StructuredData::IntegerSP
@@ -349,22 +371,22 @@ PythonInteger::CreateStructuredInteger()
 // PythonList
 //----------------------------------------------------------------------
 
-PythonList::PythonList()
-    : PythonObject(PyList_New(0))
+PythonList::PythonList(PyInitialValue value)
+    : PythonObject()
 {
+    if (value == PyInitialValue::Empty)
+        Reset(PyRefType::Owned, PyList_New(0));
 }
 
-PythonList::PythonList (PyObject *py_obj) :
-    PythonObject()
+PythonList::PythonList(PyRefType type, PyObject *py_obj)
+    : PythonObject()
 {
-    Reset(py_obj); // Use "Reset()" to ensure that py_obj is a list
+    Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
 }
 
-
-PythonList::PythonList (const PythonObject &object) :
-    PythonObject()
+PythonList::PythonList(const PythonList &list)
+    : PythonObject(list)
 {
-    Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list
 }
 
 PythonList::~PythonList ()
@@ -379,22 +401,28 @@ PythonList::Check(PyObject *py_obj)
     return PyList_Check(py_obj);
 }
 
-bool
-PythonList::Reset(PyObject *py_obj)
+void
+PythonList::Reset(PyRefType type, PyObject *py_obj)
 {
+    // Grab the desired reference type so that if we end up rejecting
+    // `py_obj` it still gets decremented if necessary.
+    PythonObject result(type, py_obj);
+
     if (!PythonList::Check(py_obj))
     {
-        PythonObject::Reset(nullptr);
-        return false;
+        PythonObject::Reset();
+        return;
     }
 
-    return PythonObject::Reset(py_obj);
+    // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
+    // back into the virtual implementation.
+    PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 uint32_t
 PythonList::GetSize() const
 {
-    if (m_py_obj)
+    if (IsValid())
         return PyList_GET_SIZE(m_py_obj);
     return 0;
 }
@@ -402,23 +430,32 @@ PythonList::GetSize() const
 PythonObject
 PythonList::GetItemAtIndex(uint32_t index) const
 {
-    if (m_py_obj)
-        return PythonObject(PyList_GetItem(m_py_obj, index));
+    if (IsValid())
+        return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
     return PythonObject();
 }
 
 void
-PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object)
+PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object)
 {
-    if (m_py_obj && object)
+    if (IsAllocated() && object.IsValid())
+    {
+        // PyList_SetItem is documented to "steal" a reference, so we need to
+        // convert it to an owned reference by incrementing it.
+        Py_INCREF(object.get());
         PyList_SetItem(m_py_obj, index, object.get());
+    }
 }
 
 void
-PythonList::AppendItem (const PythonObject &object)
+PythonList::AppendItem(const PythonObject &object)
 {
-    if (m_py_obj && object)
+    if (IsAllocated() && object.IsValid())
+    {
+        // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`
+        // here like we do with `PyList_SetItem`.
         PyList_Append(m_py_obj, object.get());
+    }
 }
 
 StructuredData::ArraySP
@@ -438,22 +475,22 @@ PythonList::CreateStructuredArray() cons
 // PythonDictionary
 //----------------------------------------------------------------------
 
-PythonDictionary::PythonDictionary()
-    : PythonObject(PyDict_New())
+PythonDictionary::PythonDictionary(PyInitialValue value)
+    : PythonObject()
 {
+    if (value == PyInitialValue::Empty)
+        Reset(PyRefType::Owned, PyDict_New());
 }
 
-PythonDictionary::PythonDictionary (PyObject *py_obj) :
-    PythonObject(py_obj)
+PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
+    : PythonObject()
 {
-    Reset(py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
+    Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
 }
 
-
-PythonDictionary::PythonDictionary (const PythonObject &object) :
-    PythonObject()
+PythonDictionary::PythonDictionary(const PythonDictionary &object)
+    : PythonObject(object)
 {
-    Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary
 }
 
 PythonDictionary::~PythonDictionary ()
@@ -469,129 +506,52 @@ PythonDictionary::Check(PyObject *py_obj
     return PyDict_Check(py_obj);
 }
 
-bool
-PythonDictionary::Reset(PyObject *py_obj)
+void
+PythonDictionary::Reset(PyRefType type, PyObject *py_obj)
 {
+    // Grab the desired reference type so that if we end up rejecting
+    // `py_obj` it still gets decremented if necessary.
+    PythonObject result(type, py_obj);
+
     if (!PythonDictionary::Check(py_obj))
     {
-        PythonObject::Reset(nullptr);
-        return false;
+        PythonObject::Reset();
+        return;
     }
 
-    return PythonObject::Reset(py_obj);
+    // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
+    // back into the virtual implementation.
+    PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 uint32_t
 PythonDictionary::GetSize() const
 {
-    if (m_py_obj)
+    if (IsValid())
         return PyDict_Size(m_py_obj);
     return 0;
 }
 
-PythonObject
-PythonDictionary::GetItemForKey (const char *key) const
-{
-    if (key && key[0])
-    {
-        PythonString python_key(key);
-        return GetItemForKey(python_key);
-    }
-    return PythonObject();
-}
-
-
-PythonObject
-PythonDictionary::GetItemForKey (const PythonString &key) const
-{
-    if (m_py_obj && key)
-        return PythonObject(PyDict_GetItem(m_py_obj, key.get()));
-    return PythonObject();
-}
-
-
-const char *
-PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fail_value) const
-{
-    if (m_py_obj && key)
-    {
-        PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get());
-        if (py_obj && PythonString::Check(py_obj))
-        {
-            PythonString str(py_obj);
-            return str.GetString().data();
-        }
-    }
-    return fail_value;
-}
-
-int64_t
-PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value) const
-{
-    if (m_py_obj && key)
-    {
-        PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get());
-        if (PythonInteger::Check(py_obj))
-        {
-            PythonInteger int_obj(py_obj);
-            return int_obj.GetInteger();
-        }
-    }
-    return fail_value;
-}
-
 PythonList
-PythonDictionary::GetKeys () const
-{
-    if (m_py_obj)
-        return PythonList(PyDict_Keys(m_py_obj));
-    return PythonList();
-}
-
-PythonString
-PythonDictionary::GetKeyAtPosition (uint32_t pos) const
+PythonDictionary::GetKeys() const
 {
-    PyObject *key, *value;
-    Py_ssize_t pos_iter = 0;
-    
-    if (m_py_obj)
-    {
-        while (PyDict_Next(m_py_obj, &pos_iter, &key, &value))
-        {
-            if (pos-- == 0)
-                return PythonString(key);
-        }
-    }
-    return PythonString();
+    if (IsValid())
+        return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
+    return PythonList(PyInitialValue::Invalid);
 }
 
 PythonObject
-PythonDictionary::GetValueAtPosition (uint32_t pos) const
+PythonDictionary::GetItemForKey(const PythonObject &key) const
 {
-    PyObject *key, *value;
-    Py_ssize_t pos_iter = 0;
-    
-    if (!m_py_obj)
-        return PythonObject();
-    
-    while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) {
-        if (pos-- == 0)
-            return PythonObject(value);
-    }
+    if (IsAllocated() && key.IsValid())
+        return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get()));
     return PythonObject();
 }
 
 void
-PythonDictionary::SetItemForKey (const PythonString &key, PyObject *value)
-{
-    if (m_py_obj && key && value)
-        PyDict_SetItem(m_py_obj, key.get(), value);
-}
-
-void
-PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value)
+PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value)
 {
-    if (m_py_obj && key && value)
+    if (IsAllocated() && key.IsValid() && value.IsValid())
         PyDict_SetItem(m_py_obj, key.get(), value.get());
 }
 
@@ -604,10 +564,9 @@ PythonDictionary::CreateStructuredDictio
     for (uint32_t i = 0; i < num_keys; ++i)
     {
         PythonObject key = keys.GetItemAtIndex(i);
-        PythonString key_str = key.Str();
         PythonObject value = GetItemForKey(key);
         StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
-        result->AddItem(key_str.GetString(), structured_value);
+        result->AddItem(key.Str().GetString(), structured_value);
     }
     return result;
 }

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h?rev=250195&r1=250194&r2=250195&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h Tue Oct 13 13:16:15 2015
@@ -25,7 +25,6 @@ namespace lldb_private {
 class PythonString;
 class PythonList;
 class PythonDictionary;
-class PythonObject;
 class PythonInteger;
 
 class StructuredPythonObject : public StructuredData::Generic
@@ -71,214 +70,240 @@ enum class PyObjectType
     String
 };
 
-    class PythonObject
+enum class PyRefType
+{
+    Borrowed, // We are not given ownership of the incoming PyObject.
+              // We cannot safely hold it without calling Py_INCREF.
+    Owned     // We have ownership of the incoming PyObject.  We should
+              // not call Py_INCREF.
+};
+
+enum class PyInitialValue
+{
+    Invalid,
+    Empty
+};
+
+class PythonObject
+{
+public:
+    PythonObject()
+        : m_py_obj(nullptr)
     {
-    public:
-        PythonObject () :
-            m_py_obj(NULL)
-        {
-        }
-        
-        explicit PythonObject (PyObject* py_obj) :
-            m_py_obj(NULL)
-        {
-            Reset (py_obj);
-        }
-        
-        PythonObject (const PythonObject &rhs) :
-            m_py_obj(NULL)
-        {
-            Reset (rhs.m_py_obj);
-        }
-
-        virtual
-        ~PythonObject ()
-        {
-            Reset (NULL);
-        }
-
-        bool
-        Reset (const PythonObject &object)
-        {
-            return Reset(object.get());
-        }
-
-        virtual bool
-        Reset (PyObject* py_obj = NULL)
-        {
-            if (py_obj != m_py_obj)
-            {
-                if (Py_IsInitialized())
-                    Py_XDECREF(m_py_obj);
-                m_py_obj = py_obj;
-                if (Py_IsInitialized())
-                    Py_XINCREF(m_py_obj);
-            }
-            return true;
-        }
-        
-        void
-        Dump () const
-        {
-            if (m_py_obj)
-                _PyObject_Dump (m_py_obj);
-            else
-                puts ("NULL");
-        }
-        
-        void
-        Dump (Stream &strm) const;
+    }
 
-        PyObject*
-        get () const
-        {
-            return m_py_obj;
-        }
+    PythonObject(PyRefType type, PyObject *py_obj)
+        : m_py_obj(nullptr)
+    {
+        Reset(type, py_obj);
+    }
 
-        PyObjectType GetObjectType() const;
+    PythonObject(const PythonObject &rhs)
+        : m_py_obj(nullptr)
+    {
+        Reset(rhs);
+    }
 
-        PythonString
-        Repr ();
-        
-        PythonString
-        Str ();
+    virtual ~PythonObject() { Reset(); }
+
+    void
+    Reset()
+    {
+        // Avoid calling the virtual method since it's not necessary
+        // to actually validate the type of the PyObject if we're
+        // just setting to null.
+        if (Py_IsInitialized())
+            Py_XDECREF(m_py_obj);
+        m_py_obj = nullptr;
+    }
+
+    void
+    Reset(const PythonObject &rhs)
+    {
+        // Avoid calling the virtual method if it's not necessary
+        // to actually validate the type of the PyObject.
+        if (!rhs.get())
+            Reset();
+        else
+            Reset(PyRefType::Borrowed, rhs.m_py_obj);
+    }
+
+    // PythonObject is implicitly convertible to PyObject *, which will call the
+    // wrong overload.  We want to explicitly disallow this, since a PyObject
+    // *always* owns its reference.  Therefore the overload which takes a
+    // PyRefType doesn't make sense, and the copy constructor should be used.
+    void
+    Reset(PyRefType type, const PythonObject &ref) = delete;
+
+    virtual void
+    Reset(PyRefType type, PyObject *py_obj)
+    {
+        if (py_obj == m_py_obj)
+            return;
+
+        if (Py_IsInitialized())
+            Py_XDECREF(m_py_obj);
+
+        m_py_obj = py_obj;
+
+        // If this is a borrowed reference, we need to convert it to
+        // an owned reference by incrementing it.  If it is an owned
+        // reference (for example the caller allocated it with PyDict_New()
+        // then we must *not* increment it.
+        if (Py_IsInitialized() && type == PyRefType::Borrowed)
+            Py_XINCREF(m_py_obj);
+    }
         
-        explicit operator bool () const
-        {
-            return m_py_obj != NULL;
-        }
+    void
+    Dump () const
+    {
+        if (m_py_obj)
+            _PyObject_Dump (m_py_obj);
+        else
+            puts ("NULL");
+    }
         
-        bool
-        IsNULLOrNone () const;
+    void
+    Dump (Stream &strm) const;
 
-        StructuredData::ObjectSP CreateStructuredObject() const;
+    PyObject*
+    get () const
+    {
+        return m_py_obj;
+    }
 
-    protected:
-        PyObject* m_py_obj;
-    };
+    PyObjectType GetObjectType() const;
 
-    class PythonString: public PythonObject
+    PythonString
+    Repr ();
+        
+    PythonString
+    Str ();
+
+    PythonObject &
+    operator=(const PythonObject &other)
     {
-    public:
-        PythonString ();
-        PythonString (PyObject *o);
-        PythonString (const PythonObject &object);
-        PythonString (llvm::StringRef string);
-        PythonString (const char *string);
-        virtual ~PythonString ();
+        Reset(PyRefType::Borrowed, other.get());
+        return *this;
+    }
 
-        static bool Check(PyObject *py_obj);
+    bool
+    IsValid() const;
 
-        virtual bool
-        Reset (PyObject* py_obj = NULL);
+    bool
+    IsAllocated() const;
 
-        llvm::StringRef
-        GetString() const;
+    bool
+    IsNone() const;
 
-        size_t
-        GetSize() const;
+    StructuredData::ObjectSP CreateStructuredObject() const;
 
-        void SetString(llvm::StringRef string);
+protected:
+    PyObject* m_py_obj;
+};
 
-        StructuredData::StringSP CreateStructuredString() const;
-    };
+class PythonString : public PythonObject
+{
+public:
+    PythonString();
+    PythonString(PyRefType type, PyObject *o);
+    PythonString(const PythonString &object);
+    explicit PythonString(llvm::StringRef string);
+    explicit PythonString(const char *string);
+    ~PythonString() override;
 
-    class PythonInteger: public PythonObject
-    {
-    public:
-        
-        PythonInteger ();
-        PythonInteger (PyObject* py_obj);
-        PythonInteger (const PythonObject &object);
-        PythonInteger (int64_t value);
-        virtual ~PythonInteger ();
+    static bool Check(PyObject *py_obj);
 
-        static bool Check(PyObject *py_obj);
+    // Bring in the no-argument base class version
+    using PythonObject::Reset;
 
-        virtual bool
-        Reset (PyObject* py_obj = NULL);
+    void Reset(PyRefType type, PyObject *py_obj) override;
 
-        int64_t GetInteger() const;
+    llvm::StringRef
+    GetString() const;
 
-        void
-        SetInteger (int64_t value);
+    size_t
+    GetSize() const;
 
-        StructuredData::IntegerSP CreateStructuredInteger() const;
-    };
-    
-    class PythonList: public PythonObject
-    {
-    public:
-      PythonList();
-        PythonList (PyObject* py_obj);
-        PythonList (const PythonObject &object);
-        virtual ~PythonList ();
+    void SetString(llvm::StringRef string);
 
-        static bool Check(PyObject *py_obj);
+    StructuredData::StringSP CreateStructuredString() const;
+};
 
-        virtual bool
-        Reset (PyObject* py_obj = NULL);
+class PythonInteger : public PythonObject
+{
+public:
+    PythonInteger();
+    PythonInteger(PyRefType type, PyObject *o);
+    PythonInteger(const PythonInteger &object);
+    explicit PythonInteger(int64_t value);
+    ~PythonInteger() override;
 
-        uint32_t GetSize() const;
+    static bool Check(PyObject *py_obj);
 
-        PythonObject GetItemAtIndex(uint32_t index) const;
+    // Bring in the no-argument base class version
+    using PythonObject::Reset;
 
-        void
-        SetItemAtIndex (uint32_t index, const PythonObject &object);
-        
-        void
-        AppendItem (const PythonObject &object);
+    void Reset(PyRefType type, PyObject *py_obj) override;
 
-        StructuredData::ArraySP CreateStructuredArray() const;
-    };
-    
-    class PythonDictionary: public PythonObject
-    {
-    public:
-        PythonDictionary();
-        PythonDictionary (PyObject* object);
-        PythonDictionary (const PythonObject &object);
-        virtual ~PythonDictionary ();
+    int64_t GetInteger() const;
 
-        static bool Check(PyObject *py_obj);
+    void
+    SetInteger (int64_t value);
 
-        virtual bool
-        Reset (PyObject* object = NULL);
+    StructuredData::IntegerSP CreateStructuredInteger() const;
+};
 
-        uint32_t GetSize() const;
+class PythonList : public PythonObject
+{
+public:
+    PythonList(PyInitialValue value);
+    PythonList(PyRefType type, PyObject *o);
+    PythonList(const PythonList &list);
+    ~PythonList() override;
 
-        PythonObject
-        GetItemForKey (const PythonString &key) const;
-        
-        const char *
-        GetItemForKeyAsString (const PythonString &key, const char *fail_value = NULL) const;
+    static bool Check(PyObject *py_obj);
 
-        int64_t
-        GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value = 0) const;
+    // Bring in the no-argument base class version
+    using PythonObject::Reset;
 
-        PythonObject
-        GetItemForKey (const char *key) const;
+    void Reset(PyRefType type, PyObject *py_obj) override;
 
-        typedef bool (*DictionaryIteratorCallback)(PythonString* key, PythonDictionary* dict);
-        
-        PythonList
-        GetKeys () const;
-        
-        PythonString
-        GetKeyAtPosition (uint32_t pos) const;
-        
-        PythonObject
-        GetValueAtPosition (uint32_t pos) const;
-        
-        void
-        SetItemForKey (const PythonString &key, PyObject *value);
+    uint32_t GetSize() const;
+
+    PythonObject GetItemAtIndex(uint32_t index) const;
 
-        void
-        SetItemForKey (const PythonString &key, const PythonObject& value);
+    void SetItemAtIndex(uint32_t index, const PythonObject &object);
 
-        StructuredData::DictionarySP CreateStructuredDictionary() const;
-    };
-    
+    void AppendItem(const PythonObject &object);
+
+    StructuredData::ArraySP CreateStructuredArray() const;
+};
+
+class PythonDictionary : public PythonObject
+{
+public:
+    PythonDictionary(PyInitialValue value);
+    PythonDictionary(PyRefType type, PyObject *o);
+    PythonDictionary(const PythonDictionary &dict);
+    ~PythonDictionary() override;
+
+    static bool Check(PyObject *py_obj);
+
+    // Bring in the no-argument base class version
+    using PythonObject::Reset;
+
+    void Reset(PyRefType type, PyObject *py_obj) override;
+
+    uint32_t GetSize() const;
+
+    PythonList GetKeys() const;
+
+    PythonObject GetItemForKey(const PythonObject &key) const;
+    void SetItemForKey(const PythonObject &key, const PythonObject &value);
+
+    StructuredData::DictionarySP CreateStructuredDictionary() const;
+};
 } // namespace lldb_private
 
 #endif  // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp?rev=250195&r1=250194&r2=250195&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp Tue Oct 13 13:16:15 2015
@@ -103,8 +103,7 @@ GetDesiredPythonHome()
 #endif
 }
 
-static std::string
-ReadPythonBacktrace (PyObject* py_backtrace);
+static std::string ReadPythonBacktrace(PythonObject py_backtrace);
 
 ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter,
                                          uint16_t on_entry,
@@ -180,27 +179,26 @@ ScriptInterpreterPython::Locker::~Locker
     DoFreeLock();
 }
 
-
-ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
-    ScriptInterpreter (interpreter, eScriptLanguagePython),
+ScriptInterpreterPython::ScriptInterpreterPython(CommandInterpreter &interpreter) :
+    ScriptInterpreter(interpreter, eScriptLanguagePython),
     IOHandlerDelegateMultiline("DONE"),
-    m_saved_stdin (),
-    m_saved_stdout (),
-    m_saved_stderr (),
-    m_main_module (),
-    m_lldb_module (),
-    m_session_dict(nullptr),
-    m_sys_module_dict(nullptr),
-    m_run_one_line_function (),
-    m_run_one_line_str_global (),
-    m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()),
-    m_terminal_state (),
-    m_active_io_handler (eIOHandlerNone),
-    m_session_is_active (false),
-    m_pty_slave_is_open (false),
-    m_valid_session (true),
-    m_lock_count (0),
-    m_command_thread_state (nullptr)
+    m_saved_stdin(),
+    m_saved_stdout(),
+    m_saved_stderr(),
+    m_main_module(),
+    m_lldb_module(),
+    m_session_dict(PyInitialValue::Invalid),
+    m_sys_module_dict(PyInitialValue::Invalid),
+    m_run_one_line_function(),
+    m_run_one_line_str_global(),
+    m_dictionary_name(interpreter.GetDebugger().GetInstanceName().AsCString()),
+    m_terminal_state(),
+    m_active_io_handler(eIOHandlerNone),
+    m_session_is_active(false),
+    m_pty_slave_is_open(false),
+    m_valid_session(true),
+    m_lock_count(0),
+    m_command_thread_state(nullptr)
 {
     assert(g_initialized && "ScriptInterpreterPython created but InitializePrivate has not been called!");
 
@@ -446,21 +444,21 @@ ScriptInterpreterPython::LeaveSession ()
     if (PyThreadState_GetDict())
     {
         PythonDictionary &sys_module_dict = GetSysModuleDictionary ();
-        if (sys_module_dict)
+        if (sys_module_dict.IsValid())
         {
-            if (m_saved_stdin)
+            if (m_saved_stdin.IsValid())
             {
-                sys_module_dict.SetItemForKey("stdin", m_saved_stdin);
+                sys_module_dict.SetItemForKey(PythonString("stdin"), m_saved_stdin);
                 m_saved_stdin.Reset ();
             }
-            if (m_saved_stdout)
+            if (m_saved_stdout.IsValid())
             {
-                sys_module_dict.SetItemForKey("stdout", m_saved_stdout);
+                sys_module_dict.SetItemForKey(PythonString("stdout"), m_saved_stdout);
                 m_saved_stdout.Reset ();
             }
-            if (m_saved_stderr)
+            if (m_saved_stderr.IsValid())
             {
-                sys_module_dict.SetItemForKey("stderr", m_saved_stderr);
+                sys_module_dict.SetItemForKey(PythonString("stderr"), m_saved_stderr);
                 m_saved_stderr.Reset ();
             }
         }
@@ -469,11 +467,12 @@ ScriptInterpreterPython::LeaveSession ()
     m_session_is_active = false;
 }
 
-static PyObject *
+static PythonObject
 PyFile_FromFile_Const(FILE *fp, const char *name, const char *mode, int (*close)(FILE *))
 {
     // Read through the Python source, doesn't seem to modify these strings
-    return PyFile_FromFile(fp, const_cast<char*>(name), const_cast<char*>(mode), close);
+    return PythonObject(PyRefType::Owned, 
+        PyFile_FromFile(fp, const_cast<char*>(name), const_cast<char*>(mode), close));
 }
 
 bool
@@ -522,7 +521,7 @@ ScriptInterpreterPython::EnterSession (u
     run_string.Clear();
 
     PythonDictionary &sys_module_dict = GetSysModuleDictionary ();
-    if (sys_module_dict)
+    if (sys_module_dict.IsValid())
     {
         lldb::StreamFileSP in_sp;
         lldb::StreamFileSP out_sp;
@@ -539,11 +538,10 @@ ScriptInterpreterPython::EnterSession (u
                 in = in_sp->GetFile().GetStream();
             if (in)
             {
-                m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin"));
+                m_saved_stdin = sys_module_dict.GetItemForKey(PythonString("stdin"));
                 // This call can deadlock your process if the file is locked
-                PyObject *new_file = PyFile_FromFile_Const (in, "", "r", nullptr);
-                sys_module_dict.SetItemForKey ("stdin", new_file);
-                Py_DECREF (new_file);
+                PythonObject new_file = PyFile_FromFile_Const(in, "", "r", nullptr);
+                sys_module_dict.SetItemForKey (PythonString("stdin"), new_file);
             }
         }
 
@@ -551,11 +549,10 @@ ScriptInterpreterPython::EnterSession (u
             out = out_sp->GetFile().GetStream();
         if (out)
         {
-            m_saved_stdout.Reset(sys_module_dict.GetItemForKey("stdout"));
+            m_saved_stdout = sys_module_dict.GetItemForKey(PythonString("stdout"));
 
-            PyObject *new_file = PyFile_FromFile_Const (out, "", "w", nullptr);
-            sys_module_dict.SetItemForKey ("stdout", new_file);
-            Py_DECREF (new_file);
+            PythonObject new_file = PyFile_FromFile_Const(out, "", "w", nullptr);
+            sys_module_dict.SetItemForKey (PythonString("stdout"), new_file);
         }
         else
             m_saved_stdout.Reset();
@@ -564,11 +561,10 @@ ScriptInterpreterPython::EnterSession (u
             err = err_sp->GetFile().GetStream();
         if (err)
         {
-            m_saved_stderr.Reset(sys_module_dict.GetItemForKey("stderr"));
+            m_saved_stderr = sys_module_dict.GetItemForKey(PythonString("stderr"));
 
-            PyObject *new_file = PyFile_FromFile_Const (err, "", "w", nullptr);
-            sys_module_dict.SetItemForKey ("stderr", new_file);
-            Py_DECREF (new_file);
+            PythonObject new_file = PyFile_FromFile_Const(err, "", "w", nullptr);
+            sys_module_dict.SetItemForKey (PythonString("stderr"), new_file);
         }
         else
             m_saved_stderr.Reset();
@@ -581,40 +577,41 @@ ScriptInterpreterPython::EnterSession (u
 }
 
 PythonObject &
-ScriptInterpreterPython::GetMainModule ()
+ScriptInterpreterPython::GetMainModule()
 {
-    if (!m_main_module)
-        m_main_module.Reset(PyImport_AddModule ("__main__"));
+    if (!m_main_module.IsValid())
+        m_main_module.Reset(PyRefType::Borrowed, PyImport_AddModule("__main__"));
     return m_main_module;
 }
 
 PythonDictionary &
 ScriptInterpreterPython::GetSessionDictionary ()
 {
-    if (!m_session_dict)
-    {
-        PythonObject &main_module = GetMainModule ();
-        if (main_module)
-        {
-            PythonDictionary main_dict(PyModule_GetDict (main_module.get()));
-            if (main_dict)
-            {
-                m_session_dict = main_dict.GetItemForKey(m_dictionary_name.c_str());
-            }
-        }
-    }
+    if (m_session_dict.IsValid())
+        return m_session_dict;
+
+    PythonObject &main_module = GetMainModule();
+    if (!main_module.IsValid())
+        return m_session_dict;
+
+    PythonDictionary main_dict(PyRefType::Borrowed, PyModule_GetDict(main_module.get()));
+    if (!main_dict.IsValid())
+        return m_session_dict;
+
+    PythonObject item = main_dict.GetItemForKey(PythonString(m_dictionary_name));
+    m_session_dict.Reset(PyRefType::Borrowed, item.get());
     return m_session_dict;
 }
 
 PythonDictionary &
 ScriptInterpreterPython::GetSysModuleDictionary ()
 {
-    if (!m_sys_module_dict)
-    {
-        PyObject *sys_module = PyImport_AddModule ("sys");
-        if (sys_module)
-            m_sys_module_dict.Reset(PyModule_GetDict (sys_module));
-    }
+    if (m_sys_module_dict.IsValid())
+        return m_sys_module_dict;
+
+    PythonObject sys_module(PyRefType::Borrowed, PyImport_AddModule("sys"));
+    if (sys_module.IsValid())
+        m_sys_module_dict.Reset(PyRefType::Borrowed, PyModule_GetDict(sys_module.get()));
     return m_sys_module_dict;
 }
 
@@ -639,20 +636,20 @@ GenerateUniqueName (const char* base_nam
 bool
 ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects ()
 {
-    if (!m_run_one_line_function)
-    {
-        PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter");
-        if (module != nullptr)
-        {
-            PythonDictionary module_dict (PyModule_GetDict (module));
-            if (module_dict)
-            {
-                m_run_one_line_function = module_dict.GetItemForKey("run_one_line");
-                m_run_one_line_str_global = module_dict.GetItemForKey("g_run_one_line_str");
-            }
-        }
-    }
-    return (bool)m_run_one_line_function;
+    if (m_run_one_line_function.IsValid())
+        return true;
+
+    PythonObject module(PyRefType::Borrowed, PyImport_AddModule ("lldb.embedded_interpreter"));
+    if (!module.IsValid())
+        return false;
+
+    PythonDictionary module_dict(PyRefType::Borrowed, PyModule_GetDict(module.get()));
+    if (!module_dict.IsValid())
+        return false;
+
+    m_run_one_line_function = module_dict.GetItemForKey(PythonString("run_one_line"));
+    m_run_one_line_str_global = module_dict.GetItemForKey(PythonString("g_run_one_line_str"));
+    return m_run_one_line_function.IsValid();
 }
 
 static void
@@ -750,19 +747,18 @@ ScriptInterpreterPython::ExecuteOneLine
         
         // Find the correct script interpreter dictionary in the main module.
         PythonDictionary &session_dict = GetSessionDictionary ();
-        if (session_dict)
+        if (session_dict.IsValid())
         {
             if (GetEmbeddedInterpreterModuleObjects ())
             {
-                PyObject *pfunc = m_run_one_line_function.get();
-                
-                if (pfunc && PyCallable_Check (pfunc))
+                if (PyCallable_Check(m_run_one_line_function.get()))
                 {
-                    PythonObject pargs (Py_BuildValue("(Os)", session_dict.get(), command));
-                    if (pargs)
+                    PythonObject pargs(PyRefType::Owned, Py_BuildValue("(Os)", session_dict.get(), command));
+                    if (pargs.IsValid())
                     {
-                        PythonObject return_value(PyObject_CallObject (pfunc, pargs.get()));
-                        if (return_value)
+                        PythonObject return_value(PyRefType::Owned,
+                            PyObject_CallObject(m_run_one_line_function.get(), pargs.get()));
+                        if (return_value.IsValid())
                             success = true;
                         else if (options.GetMaskoutErrors() && PyErr_Occurred ())
                         {
@@ -961,139 +957,140 @@ ScriptInterpreterPython::ExecuteOneLineW
                   ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0) | Locker::NoSTDIN,
                   ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
 
-    PyObject *py_return = nullptr;
-    PythonObject &main_module = GetMainModule ();
-    PythonDictionary globals (PyModule_GetDict(main_module.get()));
-    PyObject *py_error = nullptr;
+    PythonObject py_return;
+    PythonObject &main_module = GetMainModule();
+    PythonDictionary globals(PyRefType::Borrowed, PyModule_GetDict(main_module.get()));
+    PythonObject py_error;
     bool ret_success = false;
     int success;
     
     PythonDictionary locals = GetSessionDictionary ();
     
-    if (!locals)
+    if (!locals.IsValid())
     {
-        locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str());
+        locals.Reset(PyRefType::Owned, PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str()));
     }
         
-    if (!locals)
+    if (!locals.IsValid())
         locals = globals;
 
-    py_error = PyErr_Occurred();
-    if (py_error != nullptr)
+    py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
+    if (py_error.IsValid())
         PyErr_Clear();
     
     if (in_string != nullptr)
     {
         { // scope for PythonInputReaderManager
             //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
-            py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get());
-            if (py_return == nullptr)
-            { 
-                py_error = PyErr_Occurred ();
-                if (py_error != nullptr)
-                    PyErr_Clear ();
+            py_return.Reset(PyRefType::Owned, PyRun_String(in_string, Py_eval_input, globals.get(), locals.get()));
+            if (!py_return.IsValid())
+            {
+                py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
+                if (py_error.IsValid())
+                    PyErr_Clear();
 
-                py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get());
+                py_return.Reset(PyRefType::Owned, PyRun_String(in_string, Py_single_input, globals.get(), locals.get()));
             }
         }
 
-        if (py_return != nullptr)
+        if (py_return.IsValid())
         {
             switch (return_type)
             {
                 case eScriptReturnTypeCharPtr: // "char *"
                 {
                     const char format[3] = "s#";
-                    success = PyArg_Parse (py_return, format, (char **) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (char **) ret_value);
                     break;
                 }
                 case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None
                 {
                     const char format[3] = "z";
-                    success = PyArg_Parse (py_return, format, (char **) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (char **) ret_value);
                     break;
                 }
                 case eScriptReturnTypeBool:
                 {
                     const char format[2] = "b";
-                    success = PyArg_Parse (py_return, format, (bool *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (bool *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeShortInt:
                 {
                     const char format[2] = "h";
-                    success = PyArg_Parse (py_return, format, (short *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (short *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeShortIntUnsigned:
                 {
                     const char format[2] = "H";
-                    success = PyArg_Parse (py_return, format, (unsigned short *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (unsigned short *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeInt:
                 {
                     const char format[2] = "i";
-                    success = PyArg_Parse (py_return, format, (int *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (int *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeIntUnsigned:
                 {
                     const char format[2] = "I";
-                    success = PyArg_Parse (py_return, format, (unsigned int *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (unsigned int *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeLongInt:
                 {
                     const char format[2] = "l";
-                    success = PyArg_Parse (py_return, format, (long *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (long *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeLongIntUnsigned:
                 {
                     const char format[2] = "k";
-                    success = PyArg_Parse (py_return, format, (unsigned long *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (unsigned long *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeLongLong:
                 {
                     const char format[2] = "L";
-                    success = PyArg_Parse (py_return, format, (long long *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (long long *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeLongLongUnsigned:
                 {
                     const char format[2] = "K";
-                    success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (unsigned long long *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeFloat:
                 {
                     const char format[2] = "f";
-                    success = PyArg_Parse (py_return, format, (float *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (float *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeDouble:
                 {
                     const char format[2] = "d";
-                    success = PyArg_Parse (py_return, format, (double *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (double *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeChar:
                 {
                     const char format[2] = "c";
-                    success = PyArg_Parse (py_return, format, (char *) ret_value);
+                    success = PyArg_Parse (py_return.get(), format, (char *) ret_value);
                     break;
                 }
                 case eScriptReturnTypeOpaqueObject:
                 {
                     success = true;
-                    Py_XINCREF(py_return);
-                    *((PyObject**)ret_value) = py_return;
+                    PyObject *saved_value = py_return.get();
+                    Py_XINCREF(saved_value);
+                    *((PyObject **)ret_value) = saved_value;
                     break;
                 }
             }
-            Py_XDECREF (py_return);
+
             if (success)
                 ret_success = true;
             else
@@ -1101,13 +1098,13 @@ ScriptInterpreterPython::ExecuteOneLineW
         }
     }
 
-    py_error = PyErr_Occurred();
-    if (py_error != nullptr)
+    py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
+    if (py_error.IsValid())
     {
         ret_success = false;
         if (options.GetMaskoutErrors())
         {
-            if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
+            if (PyErr_GivenExceptionMatches (py_error.get(), PyExc_SyntaxError))
                 PyErr_Print ();
             PyErr_Clear();
         }
@@ -1126,71 +1123,71 @@ ScriptInterpreterPython::ExecuteMultiple
                   ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
 
     PythonObject return_value;
-    PythonObject &main_module = GetMainModule ();
-    PythonDictionary globals (PyModule_GetDict(main_module.get()));
-    PyObject *py_error = nullptr;
+    PythonObject &main_module = GetMainModule();
+    PythonDictionary globals(PyRefType::Borrowed, PyModule_GetDict(main_module.get()));
+    PythonObject py_error;
 
-    PythonDictionary locals = GetSessionDictionary ();
-    
-    if (!locals)
-    {
-        locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str());
-    }
+    PythonDictionary locals = GetSessionDictionary();
 
-    if (!locals)
-    {
+    if (!locals.IsValid())
+        locals.Reset(PyRefType::Owned, PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str()));
+
+    if (!locals.IsValid())
         locals = globals;
-    }
 
-    py_error = PyErr_Occurred();
-    if (py_error != nullptr)
+    py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
+    if (py_error.IsValid())
         PyErr_Clear();
     
     if (in_string != nullptr)
     {
+        PythonObject code_object;
+        code_object.Reset(PyRefType::Owned, Py_CompileString(in_string, "temp.py", Py_file_input));
+
+        if (code_object.IsValid())
+        {
+            // In Python 2.x, PyEval_EvalCode takes a PyCodeObject, but in Python 3.x, it takes
+            // a PyObject.  They are convertible (hence the function PyCode_Check(PyObject*), so
+            // we have to do the cast for Python 2.x
 #if PY_MAJOR_VERSION >= 3
-        PyObject *code_object = Py_CompileString(in_string, "temp.py", Py_file_input);
+            PyObject *py_code_obj = code_object.get();
 #else
-        PyCodeObject *code_object = nullptr;
-        struct _node *compiled_node = PyParser_SimpleParseString(in_string, Py_file_input);
-        if (compiled_node)
-            code_object = PyNode_Compile(compiled_node, "temp.py");
+            PyCodeObject *py_code_obj = reinterpret_cast<PyCodeObject *>(code_object.get());
 #endif
-        if (code_object)
-            return_value.Reset(PyEval_EvalCode(code_object, globals.get(), locals.get()));
+            return_value.Reset(PyRefType::Owned, PyEval_EvalCode(py_code_obj, globals.get(), locals.get()));
+        }
     }
 
-    py_error = PyErr_Occurred ();
-    if (py_error != nullptr)
+    py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
+    if (py_error.IsValid())
     {
-//        puts(in_string);
-//        _PyObject_Dump (py_error);
-//        PyErr_Print();
-//        success = false;
-        
-        PyObject *type = nullptr;
-        PyObject *value = nullptr;
-        PyObject *traceback = nullptr;
-        PyErr_Fetch (&type,&value,&traceback);
-        
+        // puts(in_string);
+        // _PyObject_Dump (py_error);
+        // PyErr_Print();
+        // success = false;
+
+        PyObject *py_type = nullptr;
+        PyObject *py_value = nullptr;
+        PyObject *py_traceback = nullptr;
+        PyErr_Fetch(&py_type, &py_value, &py_traceback);
+
+        PythonObject type(PyRefType::Owned, py_type);
+        PythonObject value(PyRefType::Owned, py_value);
+        PythonObject traceback(PyRefType::Owned, py_traceback);
+
         // get the backtrace
         std::string bt = ReadPythonBacktrace(traceback);
-        
-        if (value && value != Py_None)
+
+        if (value.IsAllocated())
         {
-            PythonString str(value);
+            PythonString str = value.Str();
             llvm::StringRef value_str(str.GetString());
             error.SetErrorStringWithFormat("%s\n%s", value_str.str().c_str(), bt.c_str());
         }
         else
             error.SetErrorStringWithFormat("%s",bt.c_str());
-        Py_XDECREF(type);
-        Py_XDECREF(value);
-        Py_XDECREF(traceback);
         if (options.GetMaskoutErrors())
-        {
             PyErr_Clear();
-        }
     }
 
     return error;
@@ -1462,53 +1459,42 @@ ScriptInterpreterPython::OSPlugin_Regist
     if (!generic)
         return nullptr;
 
-    PyObject *implementor = (PyObject *)generic->GetValue();
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)generic->GetValue());
 
-    if (implementor == nullptr || implementor == Py_None)
+    if (!implementor.IsAllocated())
         return StructuredData::DictionarySP();
 
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return StructuredData::DictionarySP();
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
         
-        Py_XDECREF(pmeth);
         return StructuredData::DictionarySP();
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
         PyErr_Print();
         PyErr_Clear();
     }
+    assert(PythonDictionary::Check(py_return.get()) && "get_register_info returned unknown object type!");
 
-    PythonDictionary result_dict(py_return);
+    PythonDictionary result_dict(PyRefType::Borrowed, py_return.get());
     return result_dict.CreateStructuredDictionary();
 }
 
@@ -1527,45 +1513,34 @@ ScriptInterpreterPython::OSPlugin_Thread
     StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
     if (!generic)
         return nullptr;
-    PyObject *implementor = (PyObject *)generic->GetValue();
 
-    if (implementor == nullptr || implementor == Py_None)
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)generic->GetValue());
+
+    if (!implementor.IsAllocated())
         return StructuredData::ArraySP();
 
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return StructuredData::ArraySP();
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
         
-        Py_XDECREF(pmeth);
         return StructuredData::ArraySP();
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
@@ -1573,8 +1548,10 @@ ScriptInterpreterPython::OSPlugin_Thread
         PyErr_Clear();
     }
 
-    PythonList ResultList(py_return);
-    return ResultList.CreateStructuredArray();
+    assert(PythonList::Check(py_return.get()) && "get_thread_info returned unknown object type!");
+
+    PythonList result_list(PyRefType::Borrowed, py_return.get());
+    return result_list.CreateStructuredArray();
 }
 
 // GetPythonValueFormatString provides a system independent type safe way to
@@ -1619,44 +1596,31 @@ ScriptInterpreterPython::OSPlugin_Regist
     StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
     if (!generic)
         return nullptr;
-    PyObject *implementor = (PyObject *)generic->GetValue();
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)generic->GetValue());
 
-    if (implementor == nullptr || implementor == Py_None)
+    if (!implementor.IsAllocated())
         return StructuredData::StringSP();
 
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return StructuredData::StringSP();
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
-        
-        Py_XDECREF(pmeth);
         return StructuredData::StringSP();
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid);
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, param_format, tid));
 
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
@@ -1664,7 +1628,10 @@ ScriptInterpreterPython::OSPlugin_Regist
         PyErr_Print();
         PyErr_Clear();
     }
-    PythonString result_string(py_return);
+
+    assert(PythonString::Check(py_return.get()) && "get_register_data returned unknown object type!");
+
+    PythonString result_string(PyRefType::Borrowed, py_return.get());
     return result_string.CreateStructuredString();
 }
 
@@ -1686,45 +1653,33 @@ ScriptInterpreterPython::OSPlugin_Create
     StructuredData::Generic *generic = os_plugin_object_sp->GetAsGeneric();
     if (!generic)
         return nullptr;
-    PyObject *implementor = (PyObject *)generic->GetValue();
 
-    if (implementor == nullptr || implementor == Py_None)
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)generic->GetValue());
+
+    if (!implementor.IsAllocated())
         return StructuredData::DictionarySP();
 
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return StructuredData::DictionarySP();
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
-        
-        Py_XDECREF(pmeth);
         return StructuredData::DictionarySP();
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, &param_format[0], tid, context);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, &param_format[0], tid, context));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
@@ -1732,7 +1687,9 @@ ScriptInterpreterPython::OSPlugin_Create
         PyErr_Clear();
     }
 
-    PythonDictionary result_dict(py_return);
+    assert(PythonDictionary::Check(py_return.get()) && "create_thread returned unknown object type!");
+
+    PythonDictionary result_dict(PyRefType::Borrowed, py_return.get());
     return result_dict.CreateStructuredDictionary();
 }
 
@@ -1846,16 +1803,15 @@ ScriptInterpreterPython::GetDynamicSetti
     if (!generic)
         return StructuredData::DictionarySP();
 
-    PyObject *reply_pyobj = nullptr;
-    
+    PythonObject reply_pyobj;
     {
         Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
         TargetSP target_sp(target->shared_from_this());
-        reply_pyobj = (PyObject *)g_swig_plugin_get(generic->GetValue(), setting_name, target_sp);
+        reply_pyobj.Reset(PyRefType::Owned,
+                          (PyObject *)g_swig_plugin_get(generic->GetValue(), setting_name, target_sp));
     }
 
-    PythonDictionary py_dict(reply_pyobj);
-
+    PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get());
     return py_dict.CreateStructuredDictionary();
 }
 
@@ -2335,63 +2291,54 @@ ScriptInterpreterPython::GetSyntheticVal
 }
 
 static std::string
-ReadPythonBacktrace (PyObject* py_backtrace)
+ReadPythonBacktrace(PythonObject py_backtrace)
 {
-    PyObject* traceback_module = nullptr,
-    *stringIO_module = nullptr,
-    *stringIO_builder = nullptr,
-    *stringIO_buffer = nullptr,
-    *printTB = nullptr,
-    *printTB_args = nullptr,
-    *printTB_result = nullptr,
-    *stringIO_getvalue = nullptr,
-    *printTB_string = nullptr;
+    PythonObject traceback_module;
+    PythonObject stringIO_module;
+    PythonObject stringIO_builder;
+    PythonObject stringIO_buffer;
+    PythonObject printTB;
+    PythonObject printTB_args;
+    PythonObject printTB_result;
+    PythonObject stringIO_getvalue;
+    PythonObject printTB_string;
 
     std::string retval("backtrace unavailable");
-    
-    if (py_backtrace && py_backtrace != Py_None)
-    {
-        traceback_module = PyImport_ImportModule("traceback");
-        stringIO_module = PyImport_ImportModule("StringIO");
-        
-        if (traceback_module && traceback_module != Py_None && stringIO_module && stringIO_module != Py_None)
-        {
-            stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO");
-            if (stringIO_builder && stringIO_builder != Py_None)
-            {
-                stringIO_buffer = PyObject_CallObject(stringIO_builder, nullptr);
-                if (stringIO_buffer && stringIO_buffer != Py_None)
-                {
-                    printTB = PyObject_GetAttrString(traceback_module, "print_tb");
-                    if (printTB && printTB != Py_None)
-                    {
-                        printTB_args = Py_BuildValue("OOO",py_backtrace,Py_None,stringIO_buffer);
-                        printTB_result = PyObject_CallObject(printTB, printTB_args);
-                        stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue");
-                        if (stringIO_getvalue && stringIO_getvalue != Py_None)
-                        {
-                            printTB_string = PyObject_CallObject (stringIO_getvalue,nullptr);
-                            if (printTB_string && PythonString::Check(printTB_string))
-                            {
-                                PythonString str(printTB_string);
-                                llvm::StringRef string_data(str.GetString());
-                                retval.assign(string_data.data(), string_data.size());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    Py_XDECREF(traceback_module);
-    Py_XDECREF(stringIO_module);
-    Py_XDECREF(stringIO_builder);
-    Py_XDECREF(stringIO_buffer);
-    Py_XDECREF(printTB);
-    Py_XDECREF(printTB_args);
-    Py_XDECREF(printTB_result);
-    Py_XDECREF(stringIO_getvalue);
-    Py_XDECREF(printTB_string);
+
+    if (!py_backtrace.IsAllocated())
+        return retval;
+
+    traceback_module.Reset(PyRefType::Owned, PyImport_ImportModule("traceback"));
+    stringIO_module.Reset(PyRefType::Owned, PyImport_ImportModule("StringIO"));
+    if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated())
+        return retval;
+
+    stringIO_builder.Reset(PyRefType::Owned, PyObject_GetAttrString(stringIO_module.get(), "StringIO"));
+    if (!stringIO_builder.IsAllocated())
+        return retval;
+
+    stringIO_buffer.Reset(PyRefType::Owned, PyObject_CallObject(stringIO_builder.get(), nullptr));
+    if (!stringIO_buffer.IsAllocated())
+        return retval;
+
+    printTB.Reset(PyRefType::Owned, PyObject_GetAttrString(traceback_module.get(), "print_tb"));
+    if (!printTB.IsAllocated())
+        return retval;
+
+    printTB_args.Reset(PyRefType::Owned, Py_BuildValue("OOO", py_backtrace.get(), Py_None, stringIO_buffer.get()));
+    printTB_result.Reset(PyRefType::Owned, PyObject_CallObject(printTB.get(), printTB_args.get()));
+    stringIO_getvalue.Reset(PyRefType::Owned, PyObject_GetAttrString(stringIO_buffer.get(), "getvalue"));
+    if (!stringIO_getvalue.IsAllocated())
+        return retval;
+
+    printTB_string.Reset(PyRefType::Owned, PyObject_CallObject(stringIO_getvalue.get(), nullptr));
+    if (!printTB_string.IsAllocated())
+        return retval;
+
+    PythonString str(PyRefType::Borrowed, printTB_string.get());
+    llvm::StringRef string_data(str.GetString());
+    retval.assign(string_data.data(), string_data.size());
+
     return retval;
 }
 
@@ -2657,7 +2604,7 @@ ScriptInterpreterPython::LoadScriptingMo
         // this call will fail if the module was not imported in this Debugger before
         command_stream.Clear();
         command_stream.Printf("sys.getrefcount(%s)",basename.c_str());
-        bool was_imported_locally = !(GetSessionDictionary().GetItemForKey(basename.c_str()).IsNULLOrNone());
+        bool was_imported_locally = GetSessionDictionary().GetItemForKey(PythonString(basename)).IsAllocated();
         
         bool was_imported = (was_imported_globally || was_imported_locally);
         
@@ -2911,46 +2858,33 @@ ScriptInterpreterPython::GetShortHelpFor
     
     if (!cmd_obj_sp)
         return false;
-    
-    PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
-    
-    if (implementor == nullptr || implementor == Py_None)
+
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)cmd_obj_sp->GetValue());
+
+    if (!implementor.IsAllocated())
         return false;
-    
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return false;
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
-        
-        Py_XDECREF(pmeth);
         return false;
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
@@ -2958,15 +2892,13 @@ ScriptInterpreterPython::GetShortHelpFor
         PyErr_Clear();
     }
 
-    if (py_return != Py_None && PythonString::Check(py_return))
+    if (py_return.IsAllocated() && PythonString::Check(py_return.get()))
     {
-        PythonString py_string(py_return);
+        PythonString py_string(PyRefType::Borrowed, py_return.get());
         llvm::StringRef return_data(py_string.GetString());
         dest.assign(return_data.data(), return_data.size());
         got_string = true;
     }
-    Py_XDECREF(py_return);
-    
     return got_string;
 }
 
@@ -2983,46 +2915,33 @@ ScriptInterpreterPython::GetFlagsForComm
     
     if (!cmd_obj_sp)
         return result;
-    
-    PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
-    
-    if (implementor == nullptr || implementor == Py_None)
+
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)cmd_obj_sp->GetValue());
+
+    if (!implementor.IsAllocated())
         return result;
-    
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return result;
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
-        
-        Py_XDECREF(pmeth);
         return result;
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
@@ -3030,12 +2949,11 @@ ScriptInterpreterPython::GetFlagsForComm
         PyErr_Clear();
     }
 
-    if (py_return != Py_None && PythonInteger::Check(py_return))
+    if (py_return.IsAllocated() && PythonInteger::Check(py_return.get()))
     {
-        PythonInteger int_value(py_return);
+        PythonInteger int_value(PyRefType::Borrowed, py_return.get());
         result = int_value.GetInteger();
     }
-    Py_XDECREF(py_return);
     
     return result;
 }
@@ -3055,46 +2973,34 @@ ScriptInterpreterPython::GetLongHelpForC
     
     if (!cmd_obj_sp)
         return false;
-    
-    PyObject* implementor = (PyObject*)cmd_obj_sp->GetValue();
-    
-    if (implementor == nullptr || implementor == Py_None)
+
+    PythonObject implementor(PyRefType::Borrowed, (PyObject *)cmd_obj_sp->GetValue());
+
+    if (!implementor.IsAllocated())
         return false;
-    
-    PyObject* pmeth  = PyObject_GetAttrString(implementor, callee_name);
-    
+
+    PythonObject pmeth(PyRefType::Owned, PyObject_GetAttrString(implementor.get(), callee_name));
+
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    if (pmeth == nullptr || pmeth == Py_None)
-    {
-        Py_XDECREF(pmeth);
+
+    if (!pmeth.IsAllocated())
         return false;
-    }
     
-    if (PyCallable_Check(pmeth) == 0)
+    if (PyCallable_Check(pmeth.get()) == 0)
     {
         if (PyErr_Occurred())
-        {
             PyErr_Clear();
-        }
         
-        Py_XDECREF(pmeth);
         return false;
     }
     
     if (PyErr_Occurred())
-    {
         PyErr_Clear();
-    }
-    
-    Py_XDECREF(pmeth);
     
     // right now we know this function exists and is callable..
-    PyObject* py_return = PyObject_CallMethod(implementor, callee_name, nullptr);
-    
+    PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+
     // if it fails, print the error but otherwise go on
     if (PyErr_Occurred())
     {
@@ -3102,14 +3008,13 @@ ScriptInterpreterPython::GetLongHelpForC
         PyErr_Clear();
     }
 
-    if (py_return != Py_None && PythonString::Check(py_return))
+    if (py_return.IsAllocated() && PythonString::Check(py_return.get()))
     {
-        PythonString str(py_return);
+        PythonString str(PyRefType::Borrowed, py_return.get());
         llvm::StringRef str_data(str.GetString());
         dest.assign(str_data.data(), str_data.size());
         got_string = true;
     }
-    Py_XDECREF(py_return);
     
     return got_string;
 }

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h?rev=250195&r1=250194&r2=250195&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h Tue Oct 13 13:16:15 2015
@@ -553,9 +553,9 @@ protected:
         eIOHandlerBreakpoint,
         eIOHandlerWatchpoint
     };
-    PythonObject &
-    GetMainModule ();
-    
+
+    PythonObject &GetMainModule();
+
     PythonDictionary &
     GetSessionDictionary ();
     
@@ -564,7 +564,7 @@ protected:
 
     bool
     GetEmbeddedInterpreterModuleObjects ();
-    
+
     PythonObject m_saved_stdin;
     PythonObject m_saved_stdout;
     PythonObject m_saved_stderr;

Modified: lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp?rev=250195&r1=250194&r2=250195&view=diff
==============================================================================
--- lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp (original)
+++ lldb/trunk/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp Tue Oct 13 13:16:15 2015
@@ -23,19 +23,75 @@ class PythonDataObjectsTest : public tes
     SetUp() override
     {
         HostInfoBase::Initialize();
-        // ScriptInterpreterPython::Initialize() depends on things like HostInfo being initialized
-        // so it can compute the python directory etc, so we need to do this after
-        // SystemInitializerCommon::Initialize().
+        // ScriptInterpreterPython::Initialize() depends on HostInfo being
+        // initializedso it can compute the python directory etc.
         ScriptInterpreterPython::Initialize();
+
+        // Although we don't care about concurrency for the purposes of running
+        // this test suite, Python requires the GIL to be locked even for
+        // deallocating memory, which can happen when you call Py_DECREF or
+        // Py_INCREF.  So acquire the GIL for the entire duration of this
+        // test suite.
+        m_gil_state = PyGILState_Ensure();
     }
 
     void
     TearDown() override
     {
+        PyGILState_Release(m_gil_state);
+
         ScriptInterpreterPython::Terminate();
     }
+
+  private:
+    PyGILState_STATE m_gil_state;
 };
 
+TEST_F(PythonDataObjectsTest, TestOwnedReferences)
+{
+    // After creating a new object, the refcount should be 1
+    PyObject *obj = PyLong_FromLong(3);
+    EXPECT_EQ(1, obj->ob_refcnt);
+
+    // If we take an owned reference, the refcount should still be 1
+    PythonObject owned_long(PyRefType::Owned, obj);
+    EXPECT_EQ(1, owned_long.get()->ob_refcnt);
+
+    // Take another reference and verify that the refcount increases
+    PythonObject strong_ref(owned_long);
+    EXPECT_EQ(2, strong_ref.get()->ob_refcnt);
+
+    // If we reset the first one, the refcount should be 1 again.
+    owned_long.Reset();
+    EXPECT_EQ(1, strong_ref.get()->ob_refcnt);
+}
+
+TEST_F(PythonDataObjectsTest, TestResetting)
+{
+    PythonDictionary dict(PyInitialValue::Empty);
+
+    PyObject *new_dict = PyDict_New();
+    dict.Reset(PyRefType::Owned, new_dict);
+    EXPECT_EQ(new_dict, dict.get());
+
+    dict.Reset(PyRefType::Owned, nullptr);
+    EXPECT_EQ(nullptr, dict.get());
+
+    dict.Reset(PyRefType::Owned, PyDict_New());
+    EXPECT_NE(nullptr, dict.get());
+    dict.Reset();
+    EXPECT_EQ(nullptr, dict.get());
+}
+
+TEST_F(PythonDataObjectsTest, TestBorrowedReferences)
+{
+    PythonInteger long_value(PyRefType::Owned, PyLong_FromLong(3));
+    EXPECT_EQ(1, long_value.get()->ob_refcnt);
+
+    PythonInteger borrowed_long(PyRefType::Borrowed, long_value.get());
+    EXPECT_EQ(2, borrowed_long.get()->ob_refcnt);
+}
+
 TEST_F(PythonDataObjectsTest, TestPythonInteger)
 {
 // Test that integers behave correctly when wrapped by a PythonInteger.
@@ -45,7 +101,7 @@ TEST_F(PythonDataObjectsTest, TestPython
     // Note that PyInt doesn't exist in Python 3.x, so this is only for 2.x
     PyObject *py_int = PyInt_FromLong(12);
     EXPECT_TRUE(PythonInteger::Check(py_int));
-    PythonInteger python_int(py_int);
+    PythonInteger python_int(PyRefType::Owned, py_int);
 
     EXPECT_EQ(PyObjectType::Integer, python_int.GetObjectType());
     EXPECT_EQ(12, python_int.GetInteger());
@@ -54,7 +110,7 @@ TEST_F(PythonDataObjectsTest, TestPython
     // Verify that `PythonInt` works correctly when given a PyLong object.
     PyObject *py_long = PyLong_FromLong(12);
     EXPECT_TRUE(PythonInteger::Check(py_long));
-    PythonInteger python_long(py_long);
+    PythonInteger python_long(PyRefType::Owned, py_long);
     EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
 
     // Verify that you can reset the value and that it is reflected properly.
@@ -74,7 +130,7 @@ TEST_F(PythonDataObjectsTest, TestPython
     // Note that PyString doesn't exist in Python 3.x, so this is only for 2.x
     PyObject *py_string = PyString_FromString(test_string);
     EXPECT_TRUE(PythonString::Check(py_string));
-    PythonString python_string(py_string);
+    PythonString python_string(PyRefType::Owned, py_string);
 
     EXPECT_EQ(PyObjectType::String, python_string.GetObjectType());
     EXPECT_STREQ(test_string, python_string.GetString().data());
@@ -83,7 +139,7 @@ TEST_F(PythonDataObjectsTest, TestPython
     // Verify that `PythonString` works correctly when given a PyUnicode object.
     PyObject *py_unicode = PyUnicode_FromString(test_string);
     EXPECT_TRUE(PythonString::Check(py_unicode));
-    PythonString python_unicode(py_unicode);
+    PythonString python_unicode(PyRefType::Owned, py_unicode);
 
     EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
     EXPECT_STREQ(test_string, python_unicode.GetString().data());
@@ -101,18 +157,17 @@ TEST_F(PythonDataObjectsTest, TestPython
     static const long long_idx0 = 5;
     static const char *const string_idx1 = "String Index 1";
 
-    PyObject *list_items[list_size];
-
     PyObject *py_list = PyList_New(2);
-    list_items[0] = PyLong_FromLong(long_idx0);
-    list_items[1] = PyString_FromString(string_idx1);
+    EXPECT_TRUE(PythonList::Check(py_list));
+    PythonList list(PyRefType::Owned, py_list);
 
-    for (int i = 0; i < list_size; ++i)
-        PyList_SetItem(py_list, i, list_items[i]);
+    PythonObject list_items[list_size];
+    list_items[0].Reset(PyRefType::Owned, PyLong_FromLong(long_idx0));
+    list_items[1].Reset(PyRefType::Owned, PyString_FromString(string_idx1));
 
-    EXPECT_TRUE(PythonList::Check(py_list));
+    for (int i = 0; i < list_size; ++i)
+        list.SetItemAtIndex(i, list_items[i]);
 
-    PythonList list(py_list);
     EXPECT_EQ(list_size, list.GetSize());
     EXPECT_EQ(PyObjectType::List, list.GetObjectType());
 
@@ -129,21 +184,20 @@ TEST_F(PythonDataObjectsTest, TestPython
     // Python API behaves correctly when wrapped by a PythonDictionary.
     static const int dict_entries = 2;
 
-    PyObject *keys[dict_entries];
-    PyObject *values[dict_entries];
+    PythonObject keys[dict_entries];
+    PythonObject values[dict_entries];
 
-    keys[0] = PyString_FromString("Key 0");
-    keys[1] = PyLong_FromLong(1);
-    values[0] = PyLong_FromLong(0);
-    values[1] = PyString_FromString("Value 1");
+    keys[0].Reset(PyRefType::Owned, PyString_FromString("Key 0"));
+    keys[1].Reset(PyRefType::Owned, PyLong_FromLong(1));
+    values[0].Reset(PyRefType::Owned, PyLong_FromLong(0));
+    values[1].Reset(PyRefType::Owned, PyString_FromString("Value 1"));
 
     PyObject *py_dict = PyDict_New();
-    for (int i = 0; i < dict_entries; ++i)
-        PyDict_SetItem(py_dict, keys[i], values[i]);
-
     EXPECT_TRUE(PythonDictionary::Check(py_dict));
+    PythonDictionary dict(PyRefType::Owned, py_dict);
 
-    PythonDictionary dict(py_dict);
+    for (int i = 0; i < dict_entries; ++i)
+        PyDict_SetItem(py_dict, keys[i].get(), values[i].get());
     EXPECT_EQ(dict.GetSize(), dict_entries);
     EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
 
@@ -162,8 +216,7 @@ TEST_F(PythonDataObjectsTest, TestPython
     static const long long_idx0 = 5;
     static const char *const string_idx1 = "String Index 1";
 
-    PyObject *py_list = PyList_New(0);
-    PythonList list(py_list);
+    PythonList list(PyInitialValue::Empty);
     PythonInteger integer(long_idx0);
     PythonString string(string_idx1);
 
@@ -184,19 +237,17 @@ TEST_F(PythonDataObjectsTest, TestPython
     // by a PythonDictionary.
     static const int dict_entries = 2;
 
-    PyObject *keys[dict_entries];
-    PyObject *values[dict_entries];
-
-    keys[0] = PyString_FromString("Key 0");
-    keys[1] = PyString_FromString("Key 1");
-    values[0] = PyLong_FromLong(1);
-    values[1] = PyString_FromString("Value 1");
+    PythonString keys[dict_entries];
+    PythonObject values[dict_entries];
 
-    PyObject *py_dict = PyDict_New();
+    keys[0].Reset(PyRefType::Owned, PyString_FromString("Key 0"));
+    keys[1].Reset(PyRefType::Owned, PyString_FromString("Key 1"));
+    values[0].Reset(PyRefType::Owned, PyLong_FromLong(1));
+    values[1].Reset(PyRefType::Owned, PyString_FromString("Value 1"));
 
-    PythonDictionary dict(py_dict);
+    PythonDictionary dict(PyInitialValue::Empty);
     for (int i = 0; i < 2; ++i)
-        dict.SetItemForKey(PythonString(keys[i]), values[i]);
+        dict.SetItemForKey(keys[i], values[i]);
 
     EXPECT_EQ(dict_entries, dict.GetSize());
 
@@ -225,9 +276,9 @@ TEST_F(PythonDataObjectsTest, TestPython
     static const char *const nested_dict_key1 = "Nested Key 1";
     static const long nested_dict_value1 = 2;
 
-    PythonList list;
-    PythonList nested_list;
-    PythonDictionary nested_dict;
+    PythonList list(PyInitialValue::Empty);
+    PythonList nested_list(PyInitialValue::Empty);
+    PythonDictionary nested_dict(PyInitialValue::Empty);
 
     nested_list.AppendItem(PythonInteger(nested_list_long_idx0));
     nested_list.AppendItem(PythonString(nested_list_str_idx1));
@@ -324,9 +375,9 @@ TEST_F(PythonDataObjectsTest, TestPython
     static const char *const nested_dict_value0 = "Nested Dict Value 0";
     static const long nested_dict_value1 = 7;
 
-    PythonDictionary dict;
-    PythonDictionary nested_dict;
-    PythonList nested_list;
+    PythonDictionary dict(PyInitialValue::Empty);
+    PythonDictionary nested_dict(PyInitialValue::Empty);
+    PythonList nested_list(PyInitialValue::Empty);
 
     nested_dict.SetItemForKey(PythonString(nested_dict_keys[0]), PythonString(nested_dict_value0));
     nested_dict.SetItemForKey(PythonString(nested_dict_keys[1]), PythonInteger(nested_dict_value1));




More information about the lldb-commits mailing list