[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, ¶m_format[0], tid, context);
-
+ PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, ¶m_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