[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-23 22:23:27 -09:00
|
|
|
//===-- PythonDataObjects.cpp ---------------------------------------------===//
|
2012-08-23 14:02:23 -08:00
|
|
|
//
|
2019-01-18 23:50:56 -09:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2012-08-23 14:02:23 -08:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2015-07-30 12:28:07 -08:00
|
|
|
#include "PythonDataObjects.h"
|
|
|
|
|
#include "ScriptInterpreterPython.h"
|
2013-06-03 10:00:07 -08:00
|
|
|
|
2013-05-22 15:04:27 -08:00
|
|
|
#include "lldb/Host/File.h"
|
2016-03-22 09:58:09 -08:00
|
|
|
#include "lldb/Host/FileSystem.h"
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
#include "lldb/Interpreter/ScriptInterpreter.h"
|
2022-02-03 03:26:10 -09:00
|
|
|
#include "lldb/Utility/LLDBLog.h"
|
2019-10-08 09:56:18 -08:00
|
|
|
#include "lldb/Utility/Log.h"
|
2017-02-02 12:39:50 -09:00
|
|
|
#include "lldb/Utility/Stream.h"
|
2015-07-30 12:28:07 -08:00
|
|
|
|
2025-08-05 07:17:01 -08:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2019-10-15 08:46:27 -08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2016-03-22 09:58:09 -08:00
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2019-03-21 11:35:55 -08:00
|
|
|
#include "llvm/Support/Errno.h"
|
2016-03-22 09:58:09 -08:00
|
|
|
|
2021-05-26 02:19:37 -08:00
|
|
|
#include <cstdio>
|
2023-05-22 12:52:09 -08:00
|
|
|
#include <variant>
|
2012-08-23 14:02:23 -08:00
|
|
|
|
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
using namespace lldb;
|
2019-10-08 09:56:18 -08:00
|
|
|
using namespace lldb_private::python;
|
2019-10-17 14:22:06 -08:00
|
|
|
using llvm::cantFail;
|
2019-10-08 09:56:18 -08:00
|
|
|
using llvm::Error;
|
|
|
|
|
using llvm::Expected;
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
using llvm::Twine;
|
2019-10-08 09:56:18 -08:00
|
|
|
|
|
|
|
|
template <> Expected<bool> python::As<bool>(Expected<PythonObject> &&obj) {
|
|
|
|
|
if (!obj)
|
|
|
|
|
return obj.takeError();
|
|
|
|
|
return obj.get().IsTrue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {
|
|
|
|
|
if (!obj)
|
|
|
|
|
return obj.takeError();
|
2020-05-08 09:56:30 -08:00
|
|
|
return obj->AsLongLong();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
Expected<unsigned long long>
|
|
|
|
|
python::As<unsigned long long>(Expected<PythonObject> &&obj) {
|
|
|
|
|
if (!obj)
|
|
|
|
|
return obj.takeError();
|
|
|
|
|
return obj->AsUnsignedLongLong();
|
2019-10-08 09:56:18 -08:00
|
|
|
}
|
2012-08-23 14:02:23 -08:00
|
|
|
|
2019-10-17 14:22:06 -08:00
|
|
|
template <>
|
|
|
|
|
Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {
|
|
|
|
|
if (!obj)
|
|
|
|
|
return obj.takeError();
|
|
|
|
|
PyObject *str_obj = PyObject_Str(obj.get().get());
|
2024-04-22 19:17:51 -08:00
|
|
|
if (!str_obj)
|
2019-10-17 14:22:06 -08:00
|
|
|
return llvm::make_error<PythonException>();
|
|
|
|
|
auto str = Take<PythonString>(str_obj);
|
|
|
|
|
auto utf8 = str.AsUTF8();
|
|
|
|
|
if (!utf8)
|
|
|
|
|
return utf8.takeError();
|
2020-01-28 14:06:33 -09:00
|
|
|
return std::string(utf8.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 01:59:19 -09:00
|
|
|
void PythonObject::Reset() {
|
|
|
|
|
if (m_py_obj && Py_IsInitialized()) {
|
2025-08-06 08:06:54 -08:00
|
|
|
PyGILState_STATE state = PyGILState_Ensure();
|
|
|
|
|
Py_DECREF(m_py_obj);
|
|
|
|
|
PyGILState_Release(state);
|
2022-01-19 01:59:19 -09:00
|
|
|
}
|
|
|
|
|
m_py_obj = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
Expected<long long> PythonObject::AsLongLong() const {
|
|
|
|
|
if (!m_py_obj)
|
|
|
|
|
return nullDeref();
|
|
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
|
long long r = PyLong_AsLongLong(m_py_obj);
|
|
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
return exception();
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-22 12:52:09 -08:00
|
|
|
Expected<unsigned long long> PythonObject::AsUnsignedLongLong() const {
|
2020-05-08 09:56:30 -08:00
|
|
|
if (!m_py_obj)
|
|
|
|
|
return nullDeref();
|
|
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
|
long long r = PyLong_AsUnsignedLongLong(m_py_obj);
|
|
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
return exception();
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wraps on overflow, instead of raising an error.
|
|
|
|
|
Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const {
|
|
|
|
|
if (!m_py_obj)
|
|
|
|
|
return nullDeref();
|
|
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
|
unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);
|
2023-05-22 12:52:09 -08:00
|
|
|
// FIXME: We should fetch the exception message and hoist it.
|
2020-05-08 09:56:30 -08:00
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
return exception();
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 09:41:48 -08:00
|
|
|
void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {
|
|
|
|
|
s.value(llvm::formatv("Python Obj: {0:X}", GetValue()).str());
|
2015-03-17 12:04:04 -08:00
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
// PythonObject
|
2012-08-23 14:02:23 -08:00
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
void PythonObject::Dump(Stream &strm) const {
|
2025-08-05 07:17:01 -08:00
|
|
|
if (!m_py_obj) {
|
|
|
|
|
strm << "NULL";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject *py_str = PyObject_Repr(m_py_obj);
|
|
|
|
|
if (!py_str)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-01-02 19:42:56 -09:00
|
|
|
llvm::scope_exit release_py_str([py_str] { Py_DECREF(py_str); });
|
2025-08-05 07:17:01 -08:00
|
|
|
|
|
|
|
|
PyObject *py_bytes = PyUnicode_AsEncodedString(py_str, "utf-8", "replace");
|
|
|
|
|
if (!py_bytes)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-01-02 19:42:56 -09:00
|
|
|
llvm::scope_exit release_py_bytes([py_bytes] { Py_DECREF(py_bytes); });
|
2025-08-05 07:17:01 -08:00
|
|
|
|
|
|
|
|
char *buffer = nullptr;
|
|
|
|
|
Py_ssize_t length = 0;
|
|
|
|
|
if (PyBytes_AsStringAndSize(py_bytes, &buffer, &length) == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
strm << llvm::StringRef(buffer, length);
|
2013-05-22 15:04:27 -08:00
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
PyObjectType PythonObject::GetObjectType() const {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (!IsAllocated())
|
2015-03-17 12:04:04 -08:00
|
|
|
return PyObjectType::None;
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
if (PythonModule::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::Module;
|
2015-10-14 13:06:13 -08:00
|
|
|
if (PythonList::Check(m_py_obj))
|
2015-03-17 12:04:04 -08:00
|
|
|
return PyObjectType::List;
|
2015-11-11 10:42:27 -09:00
|
|
|
if (PythonTuple::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::Tuple;
|
2015-10-14 13:06:13 -08:00
|
|
|
if (PythonDictionary::Check(m_py_obj))
|
2015-03-17 12:04:04 -08:00
|
|
|
return PyObjectType::Dictionary;
|
2015-10-14 13:06:13 -08:00
|
|
|
if (PythonString::Check(m_py_obj))
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
return PyObjectType::String;
|
2016-01-11 13:16:12 -09:00
|
|
|
if (PythonBytes::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::Bytes;
|
2016-01-25 14:21:09 -09:00
|
|
|
if (PythonByteArray::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::ByteArray;
|
2019-02-16 09:39:14 -09:00
|
|
|
if (PythonBoolean::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::Boolean;
|
2015-10-14 13:06:13 -08:00
|
|
|
if (PythonInteger::Check(m_py_obj))
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
return PyObjectType::Integer;
|
2015-10-15 11:35:48 -08:00
|
|
|
if (PythonFile::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::File;
|
2015-11-11 10:42:27 -09:00
|
|
|
if (PythonCallable::Check(m_py_obj))
|
|
|
|
|
return PyObjectType::Callable;
|
2015-03-17 12:04:04 -08:00
|
|
|
return PyObjectType::Unknown;
|
|
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
PythonString PythonObject::Repr() const {
|
2013-07-12 13:11:02 -08:00
|
|
|
if (!m_py_obj)
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonString();
|
2013-07-12 13:11:02 -08:00
|
|
|
PyObject *repr = PyObject_Repr(m_py_obj);
|
|
|
|
|
if (!repr)
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonString();
|
|
|
|
|
return PythonString(PyRefType::Owned, repr);
|
2013-07-12 13:11:02 -08:00
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
PythonString PythonObject::Str() const {
|
2013-07-12 13:11:02 -08:00
|
|
|
if (!m_py_obj)
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonString();
|
2013-07-12 13:11:02 -08:00
|
|
|
PyObject *str = PyObject_Str(m_py_obj);
|
|
|
|
|
if (!str)
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonString();
|
|
|
|
|
return PythonString(PyRefType::Owned, str);
|
2013-07-12 13:11:02 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
PythonObject
|
2015-11-12 08:01:48 -09:00
|
|
|
PythonObject::ResolveNameWithDictionary(llvm::StringRef name,
|
|
|
|
|
const PythonDictionary &dict) {
|
2019-03-28 10:10:14 -08:00
|
|
|
size_t dot_pos = name.find('.');
|
2015-11-11 10:42:27 -09:00
|
|
|
llvm::StringRef piece = name.substr(0, dot_pos);
|
|
|
|
|
PythonObject result = dict.GetItemForKey(PythonString(piece));
|
2015-11-11 08:59:49 -09:00
|
|
|
if (dot_pos == llvm::StringRef::npos) {
|
2015-11-11 10:42:27 -09:00
|
|
|
// There was no dot, we're done.
|
2016-01-11 13:16:12 -09:00
|
|
|
return result;
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
// There was a dot. The remaining portion of the name should be looked up in
|
|
|
|
|
// the context of the object that was found in the dictionary.
|
|
|
|
|
return result.ResolveName(name.substr(dot_pos + 1));
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
PythonObject PythonObject::ResolveName(llvm::StringRef name) const {
|
2018-04-30 08:49:04 -08:00
|
|
|
// Resolve the name in the context of the specified object. If, for example,
|
|
|
|
|
// `this` refers to a PyModule, then this will look for `name` in this
|
|
|
|
|
// module. If `this` refers to a PyType, then it will resolve `name` as an
|
|
|
|
|
// attribute of that type. If `this` refers to an instance of an object,
|
|
|
|
|
// then it will resolve `name` as the value of the specified field.
|
2016-09-06 12:57:50 -08:00
|
|
|
//
|
2015-11-11 08:59:49 -09:00
|
|
|
// This function handles dotted names so that, for example, if `m_py_obj`
|
2018-04-30 08:49:04 -08:00
|
|
|
// refers to the `sys` module, and `name` == "path.append", then it will find
|
|
|
|
|
// the function `sys.path.append`.
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2019-03-28 10:10:14 -08:00
|
|
|
size_t dot_pos = name.find('.');
|
2015-11-11 10:42:27 -09:00
|
|
|
if (dot_pos == llvm::StringRef::npos) {
|
2018-04-30 08:49:04 -08:00
|
|
|
// No dots in the name, we should be able to find the value immediately as
|
|
|
|
|
// an attribute of `m_py_obj`.
|
2015-11-11 10:42:27 -09:00
|
|
|
return GetAttributeValue(name);
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
// Look up the first piece of the name, and resolve the rest as a child of
|
2016-09-06 12:57:50 -08:00
|
|
|
// that.
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject parent = ResolveName(name.substr(0, dot_pos));
|
2015-11-11 08:59:49 -09:00
|
|
|
if (!parent.IsAllocated())
|
|
|
|
|
return PythonObject();
|
2015-11-11 10:42:27 -09:00
|
|
|
|
|
|
|
|
// Tail recursion.. should be optimized by the compiler
|
|
|
|
|
return parent.ResolveName(name.substr(dot_pos + 1));
|
2015-11-11 08:59:49 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PythonObject::HasAttribute(llvm::StringRef attr) const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return false;
|
|
|
|
|
PythonString py_attr(attr);
|
|
|
|
|
return !!PyObject_HasAttr(m_py_obj, py_attr.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return PythonObject();
|
|
|
|
|
|
|
|
|
|
PythonString py_attr(attr);
|
|
|
|
|
if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
|
|
|
|
|
return PythonObject();
|
|
|
|
|
|
2015-10-15 11:35:48 -08:00
|
|
|
return PythonObject(PyRefType::Owned,
|
|
|
|
|
PyObject_GetAttr(m_py_obj, py_attr.get()));
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 09:51:49 -08:00
|
|
|
StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {
|
|
|
|
|
switch (GetObjectType()) {
|
|
|
|
|
case PyObjectType::Dictionary:
|
|
|
|
|
return PythonDictionary(PyRefType::Borrowed, m_py_obj)
|
|
|
|
|
.CreateStructuredDictionary();
|
2019-02-16 09:39:14 -09:00
|
|
|
case PyObjectType::Boolean:
|
|
|
|
|
return PythonBoolean(PyRefType::Borrowed, m_py_obj)
|
|
|
|
|
.CreateStructuredBoolean();
|
2023-05-22 12:52:09 -08:00
|
|
|
case PyObjectType::Integer: {
|
|
|
|
|
StructuredData::IntegerSP int_sp =
|
|
|
|
|
PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger();
|
|
|
|
|
if (std::holds_alternative<StructuredData::UnsignedIntegerSP>(int_sp))
|
|
|
|
|
return std::get<StructuredData::UnsignedIntegerSP>(int_sp);
|
|
|
|
|
if (std::holds_alternative<StructuredData::SignedIntegerSP>(int_sp))
|
|
|
|
|
return std::get<StructuredData::SignedIntegerSP>(int_sp);
|
|
|
|
|
return nullptr;
|
|
|
|
|
};
|
2015-03-17 12:04:04 -08:00
|
|
|
case PyObjectType::List:
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
|
2015-03-17 12:04:04 -08:00
|
|
|
case PyObjectType::String:
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
|
2016-01-11 13:16:12 -09:00
|
|
|
case PyObjectType::Bytes:
|
|
|
|
|
return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
|
2016-01-25 14:21:09 -09:00
|
|
|
case PyObjectType::ByteArray:
|
|
|
|
|
return PythonByteArray(PyRefType::Borrowed, m_py_obj)
|
|
|
|
|
.CreateStructuredString();
|
2015-03-17 12:04:04 -08:00
|
|
|
case PyObjectType::None:
|
|
|
|
|
return StructuredData::ObjectSP();
|
|
|
|
|
default:
|
2022-01-17 01:29:35 -09:00
|
|
|
return StructuredData::ObjectSP(new StructuredPythonObject(
|
|
|
|
|
PythonObject(PyRefType::Borrowed, m_py_obj)));
|
2015-03-17 12:04:04 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-11 13:16:12 -09:00
|
|
|
// PythonString
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) { SetBytes(bytes); }
|
2016-01-11 13:16:12 -09:00
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) {
|
2016-01-11 13:16:12 -09:00
|
|
|
SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PythonBytes::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
2018-12-14 15:15:33 -09:00
|
|
|
return PyBytes_Check(py_obj);
|
2016-01-11 13:16:12 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return llvm::ArrayRef<uint8_t>();
|
|
|
|
|
|
|
|
|
|
Py_ssize_t size;
|
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
|
|
PyBytes_AsStringAndSize(m_py_obj, &c, &size);
|
|
|
|
|
return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t PythonBytes::GetSize() const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return 0;
|
|
|
|
|
return PyBytes_Size(m_py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {
|
|
|
|
|
const char *data = reinterpret_cast<const char *>(bytes.data());
|
2019-10-21 18:32:37 -08:00
|
|
|
*this = Take<PythonBytes>(PyBytes_FromStringAndSize(data, bytes.size()));
|
2016-01-11 13:16:12 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::StringSP PythonBytes::CreateStructuredString() const {
|
|
|
|
|
StructuredData::StringSP result(new StructuredData::String);
|
|
|
|
|
Py_ssize_t size;
|
|
|
|
|
char *c;
|
|
|
|
|
PyBytes_AsStringAndSize(m_py_obj, &c, &size);
|
|
|
|
|
result->SetValue(std::string(c, size));
|
|
|
|
|
return result;
|
2016-01-25 14:21:09 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)
|
|
|
|
|
: PythonByteArray(bytes.data(), bytes.size()) {}
|
|
|
|
|
|
|
|
|
|
PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
|
|
|
|
|
const char *str = reinterpret_cast<const char *>(bytes);
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonByteArray>(PyByteArray_FromStringAndSize(str, length));
|
2016-01-25 14:21:09 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PythonByteArray::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
2018-12-14 15:15:33 -09:00
|
|
|
return PyByteArray_Check(py_obj);
|
2016-01-25 14:21:09 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return llvm::ArrayRef<uint8_t>();
|
|
|
|
|
|
|
|
|
|
char *c = PyByteArray_AsString(m_py_obj);
|
|
|
|
|
size_t size = GetSize();
|
|
|
|
|
return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t PythonByteArray::GetSize() const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return PyByteArray_Size(m_py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::StringSP PythonByteArray::CreateStructuredString() const {
|
|
|
|
|
StructuredData::StringSP result(new StructuredData::String);
|
|
|
|
|
llvm::ArrayRef<uint8_t> bytes = GetBytes();
|
|
|
|
|
const char *str = reinterpret_cast<const char *>(bytes.data());
|
|
|
|
|
result->SetValue(std::string(str, bytes.size()));
|
|
|
|
|
return result;
|
2016-01-11 13:16:12 -09:00
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
// PythonString
|
|
|
|
|
|
2019-10-08 09:56:18 -08:00
|
|
|
Expected<PythonString> PythonString::FromUTF8(llvm::StringRef string) {
|
|
|
|
|
PyObject *str = PyUnicode_FromStringAndSize(string.data(), string.size());
|
|
|
|
|
if (!str)
|
|
|
|
|
return llvm::make_error<PythonException>();
|
|
|
|
|
return Take<PythonString>(str);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonString::PythonString(llvm::StringRef string) { SetString(string); }
|
2012-08-23 14:02:23 -08:00
|
|
|
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
bool PythonString::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
2015-10-14 13:06:13 -08:00
|
|
|
|
2015-10-16 09:51:49 -08:00
|
|
|
if (PyUnicode_Check(py_obj))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
llvm::StringRef PythonString::GetString() const {
|
2019-10-08 09:56:18 -08:00
|
|
|
auto s = AsUTF8();
|
|
|
|
|
if (!s) {
|
|
|
|
|
llvm::consumeError(s.takeError());
|
|
|
|
|
return llvm::StringRef("");
|
|
|
|
|
}
|
|
|
|
|
return s.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expected<llvm::StringRef> PythonString::AsUTF8() const {
|
2015-10-14 13:06:13 -08:00
|
|
|
if (!IsValid())
|
2019-10-08 09:56:18 -08:00
|
|
|
return nullDeref();
|
2015-10-14 13:06:13 -08:00
|
|
|
|
2025-08-08 12:57:58 -08:00
|
|
|
// PyUnicode_AsUTF8AndSize caches the UTF-8 representation of the string in
|
|
|
|
|
// the Unicode object, which makes it more efficient and ties the lifetime of
|
|
|
|
|
// the data to the Python string. However, it was only added to the Stable API
|
|
|
|
|
// in Python 3.10. Older versions that want to use the Stable API must use
|
|
|
|
|
// PyUnicode_AsUTF8String in combination with ConstString.
|
|
|
|
|
#if defined(Py_LIMITED_API) && (Py_LIMITED_API < 0x030a0000)
|
|
|
|
|
PyObject *py_bytes = PyUnicode_AsUTF8String(m_py_obj);
|
|
|
|
|
if (!py_bytes)
|
|
|
|
|
return exception();
|
2026-01-02 19:42:56 -09:00
|
|
|
llvm::scope_exit release_py_str([py_bytes] { Py_DECREF(py_bytes); });
|
2025-08-08 12:57:58 -08:00
|
|
|
Py_ssize_t size = PyBytes_Size(py_bytes);
|
|
|
|
|
const char *str = PyBytes_AsString(py_bytes);
|
2015-10-14 13:06:13 -08:00
|
|
|
|
2025-08-08 12:57:58 -08:00
|
|
|
if (!str)
|
|
|
|
|
return exception();
|
|
|
|
|
|
|
|
|
|
return ConstString(str, size).GetStringRef();
|
|
|
|
|
#else
|
|
|
|
|
Py_ssize_t size;
|
|
|
|
|
const char *str = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
|
2019-10-08 09:56:18 -08:00
|
|
|
|
2025-08-08 12:57:58 -08:00
|
|
|
if (!str)
|
2019-10-08 09:56:18 -08:00
|
|
|
return exception();
|
|
|
|
|
|
2025-08-08 12:57:58 -08:00
|
|
|
return llvm::StringRef(str, size);
|
|
|
|
|
#endif
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
size_t PythonString::GetSize() const {
|
2025-08-05 15:19:59 -08:00
|
|
|
if (IsValid())
|
2020-08-04 09:52:48 -08:00
|
|
|
return PyUnicode_GetLength(m_py_obj);
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
return 0;
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
void PythonString::SetString(llvm::StringRef string) {
|
2019-10-08 09:56:18 -08:00
|
|
|
auto s = FromUTF8(string);
|
|
|
|
|
if (!s) {
|
|
|
|
|
llvm::consumeError(s.takeError());
|
|
|
|
|
Reset();
|
|
|
|
|
} else {
|
2019-10-17 14:22:09 -08:00
|
|
|
*this = std::move(s.get());
|
2019-10-08 09:56:18 -08:00
|
|
|
}
|
2015-03-17 12:04:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::StringSP PythonString::CreateStructuredString() const {
|
|
|
|
|
StructuredData::StringSP result(new StructuredData::String);
|
|
|
|
|
result->SetValue(GetString());
|
|
|
|
|
return result;
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
// PythonInteger
|
2012-08-23 15:49:47 -08:00
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonInteger::PythonInteger(int64_t value) { SetInteger(value); }
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
bool PythonInteger::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
2018-04-30 08:49:04 -08:00
|
|
|
// Python 3 does not have PyInt_Check. There is only one type of integral
|
|
|
|
|
// value, long.
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
return PyLong_Check(py_obj);
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
void PythonInteger::SetInteger(int64_t value) {
|
2019-10-21 18:32:37 -08:00
|
|
|
*this = Take<PythonInteger>(PyLong_FromLongLong(value));
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
|
2023-05-22 12:52:09 -08:00
|
|
|
StructuredData::UnsignedIntegerSP uint_sp = CreateStructuredUnsignedInteger();
|
|
|
|
|
return uint_sp ? StructuredData::IntegerSP(uint_sp)
|
|
|
|
|
: CreateStructuredSignedInteger();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::UnsignedIntegerSP
|
|
|
|
|
PythonInteger::CreateStructuredUnsignedInteger() const {
|
|
|
|
|
StructuredData::UnsignedIntegerSP result = nullptr;
|
|
|
|
|
llvm::Expected<unsigned long long> value = AsUnsignedLongLong();
|
|
|
|
|
if (!value)
|
2020-05-08 09:56:30 -08:00
|
|
|
llvm::consumeError(value.takeError());
|
2023-05-22 12:52:09 -08:00
|
|
|
else
|
|
|
|
|
result = std::make_shared<StructuredData::UnsignedInteger>(value.get());
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::SignedIntegerSP
|
|
|
|
|
PythonInteger::CreateStructuredSignedInteger() const {
|
|
|
|
|
StructuredData::SignedIntegerSP result = nullptr;
|
|
|
|
|
llvm::Expected<long long> value = AsLongLong();
|
|
|
|
|
if (!value)
|
|
|
|
|
llvm::consumeError(value.takeError());
|
|
|
|
|
else
|
|
|
|
|
result = std::make_shared<StructuredData::SignedInteger>(value.get());
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-16 09:39:14 -09:00
|
|
|
// PythonBoolean
|
|
|
|
|
|
2025-08-01 14:27:14 -08:00
|
|
|
PythonBoolean::PythonBoolean(bool value) { SetValue(value); }
|
2019-02-16 09:39:14 -09:00
|
|
|
|
|
|
|
|
bool PythonBoolean::Check(PyObject *py_obj) {
|
|
|
|
|
return py_obj ? PyBool_Check(py_obj) : false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PythonBoolean::GetValue() const {
|
|
|
|
|
return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PythonBoolean::SetValue(bool value) {
|
2019-10-21 18:32:37 -08:00
|
|
|
*this = Take<PythonBoolean>(PyBool_FromLong(value));
|
2019-02-16 09:39:14 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {
|
|
|
|
|
StructuredData::BooleanSP result(new StructuredData::Boolean);
|
|
|
|
|
result->SetValue(GetValue());
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
// PythonList
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonList::PythonList(PyInitialValue value) {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (value == PyInitialValue::Empty)
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonList>(PyList_New(0));
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonList::PythonList(int list_size) {
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonList>(PyList_New(list_size));
|
2015-10-14 08:59:44 -08:00
|
|
|
}
|
|
|
|
|
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
bool PythonList::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
return PyList_Check(py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
uint32_t PythonList::GetSize() const {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (IsValid())
|
2025-08-01 06:57:34 -08:00
|
|
|
return PyList_Size(m_py_obj);
|
2012-08-23 14:02:23 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
PythonObject PythonList::GetItemAtIndex(uint32_t index) const {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (IsValid())
|
|
|
|
|
return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));
|
2014-01-27 14:43:24 -09:00
|
|
|
return PythonObject();
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &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());
|
2014-01-27 14:43:24 -09:00
|
|
|
PyList_SetItem(m_py_obj, index, object.get());
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
}
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
void PythonList::AppendItem(const PythonObject &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`.
|
2014-01-27 14:43:24 -09:00
|
|
|
PyList_Append(m_py_obj, object.get());
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
}
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
StructuredData::ArraySP PythonList::CreateStructuredArray() const {
|
|
|
|
|
StructuredData::ArraySP result(new StructuredData::Array);
|
|
|
|
|
uint32_t count = GetSize();
|
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
|
PythonObject obj = GetItemAtIndex(i);
|
|
|
|
|
result->AddItem(obj.CreateStructuredObject());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
// PythonTuple
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonTuple::PythonTuple(PyInitialValue value) {
|
2015-11-11 10:42:27 -09:00
|
|
|
if (value == PyInitialValue::Empty)
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonTuple>(PyTuple_New(0));
|
2015-11-11 10:42:27 -09:00
|
|
|
}
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonTuple::PythonTuple(int tuple_size) {
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonTuple>(PyTuple_New(tuple_size));
|
2015-11-11 10:42:27 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
|
|
|
|
|
m_py_obj = PyTuple_New(objects.size());
|
|
|
|
|
|
|
|
|
|
uint32_t idx = 0;
|
|
|
|
|
for (auto object : objects) {
|
|
|
|
|
if (object.IsValid())
|
|
|
|
|
SetItemAtIndex(idx, object);
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {
|
|
|
|
|
m_py_obj = PyTuple_New(objects.size());
|
|
|
|
|
|
|
|
|
|
uint32_t idx = 0;
|
|
|
|
|
for (auto py_object : objects) {
|
|
|
|
|
PythonObject object(PyRefType::Borrowed, py_object);
|
|
|
|
|
if (object.IsValid())
|
|
|
|
|
SetItemAtIndex(idx, object);
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PythonTuple::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
return PyTuple_Check(py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t PythonTuple::GetSize() const {
|
|
|
|
|
if (IsValid())
|
2025-08-01 06:57:34 -08:00
|
|
|
return PyTuple_Size(m_py_obj);
|
2015-11-11 10:42:27 -09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {
|
|
|
|
|
if (IsValid())
|
|
|
|
|
return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));
|
|
|
|
|
return PythonObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {
|
|
|
|
|
if (IsAllocated() && object.IsValid()) {
|
|
|
|
|
// PyTuple_SetItem is documented to "steal" a reference, so we need to
|
|
|
|
|
// convert it to an owned reference by incrementing it.
|
|
|
|
|
Py_INCREF(object.get());
|
|
|
|
|
PyTuple_SetItem(m_py_obj, index, object.get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {
|
|
|
|
|
StructuredData::ArraySP result(new StructuredData::Array);
|
|
|
|
|
uint32_t count = GetSize();
|
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
|
PythonObject obj = GetItemAtIndex(i);
|
|
|
|
|
result->AddItem(obj.CreateStructuredObject());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
// PythonDictionary
|
|
|
|
|
|
2019-10-15 09:12:49 -08:00
|
|
|
PythonDictionary::PythonDictionary(PyInitialValue value) {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (value == PyInitialValue::Empty)
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
*this = Take<PythonDictionary>(PyDict_New());
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
Port native Python-API to 3.x
With this change, liblldb is 95% of the way towards being able
to work under both Python 2.x and Python 3.x. This should
introduce no functional change for Python 2.x, but for Python
3.x there are some important changes. Primarily, these are:
1) PyString doesn't exist in Python 3. Everything is a PyUnicode.
To account for this, PythonString now stores a PyBytes instead
of a PyString. In Python 2, this is equivalent to a PyUnicode,
and in Python 3, we do a conversion from PyUnicode to PyBytes
and store the PyBytes.
2) PyInt doesn't exist in Python 3. Everything is a PyLong. To
account for this, PythonInteger stores a PyLong instead of a
PyInt. In Python 2.x, this requires doing a conversion to
PyLong when creating a PythonInteger from a PyInt. In 3.x,
there is no PyInt anyway, so we can assume everything is a
PyLong.
3) PyFile_FromFile doesn't exist in Python 3. Instead there is a
PyFile_FromFd. This is not addressed in this patch because it
will require quite a large change to plumb fd's all the way
through the system into the ScriptInterpreter. This is the only
remaining piece of the puzzle to get LLDB supporting Python 3.x.
Being able to run the test suite is not addressed in this patch.
After the extension module can compile and you can enter an embedded
3.x interpreter, the test suite will be addressed in a followup.
llvm-svn: 249886
2015-10-09 11:45:41 -08:00
|
|
|
bool PythonDictionary::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return PyDict_Check(py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-07 21:01:21 -09:00
|
|
|
bool PythonDictionary::HasKey(const llvm::Twine &key) const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
PythonString key_object(key.isSingleStringRef() ? key.getSingleStringRef()
|
|
|
|
|
: key.str());
|
|
|
|
|
|
|
|
|
|
if (int res = PyDict_Contains(m_py_obj, key_object.get()) > 0)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
uint32_t PythonDictionary::GetSize() const {
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
if (IsValid())
|
<rdar://problem/13010007>
Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:
class OperatingSystemPlugin:
def create_thread(self, tid, context):
# Return a dictionary for a new thread to create it on demand
This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.
Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*.
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
- PyObject *
- const PythonObject &
- const lldb::ScriptInterpreterObjectSP &
Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.
llvm-svn: 172873
2013-01-18 14:41:08 -09:00
|
|
|
return PyDict_Size(m_py_obj);
|
2012-08-23 14:02:23 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
PythonList PythonDictionary::GetKeys() const {
|
|
|
|
|
if (IsValid())
|
|
|
|
|
return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));
|
|
|
|
|
return PythonList(PyInitialValue::Invalid);
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {
|
2019-10-17 14:22:06 -08:00
|
|
|
auto item = GetItem(key);
|
|
|
|
|
if (!item) {
|
|
|
|
|
llvm::consumeError(item.takeError());
|
|
|
|
|
return PythonObject();
|
|
|
|
|
}
|
|
|
|
|
return std::move(item.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expected<PythonObject>
|
|
|
|
|
PythonDictionary::GetItem(const PythonObject &key) const {
|
[lldb] Reject NULL key in PythonDictionary::GetItem (#205753)
A `breakpoint set -P <class>` with an invalid-UTF-8 class name crashes
lldb with `EXC_BAD_ACCESS`. The class name is passed through
unmodified, so the byte sequence `\xd0p` (an incomplete two-byte UTF-8
sequence) reaches the Python layer:
```
./bin/lldb -b -o $'breakpoint set -P \xd0p -f main.cpp' ./bin/lldb
...
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/
Stack dump:
#4 PythonDictionary::GetItem(PythonObject const&) const
#6 PythonDictionary::GetItemForKey(PythonObject const&) const
#7 PythonObject::ResolveNameWithDictionary(StringRef, PythonDictionary const&)
#9 ScriptedPythonInterface::CreatePluginObject<...>(...)
```
`ResolveNameWithDictionary` builds a `PythonString` from the class name
and looks it up in the module dictionary. When the name is not valid
UTF-8, `PyUnicode_FromStringAndSize` returns `NULL`, so the
`PythonString` is left with `m_py_obj == NULL`. `GetItemForKey` forwards
that object to `GetItem`, which passed the `NULL` `PyObject *` straight
to `PyDict_GetItemWithError`.
Debugging the crashing lldb under lldb shows the `NULL` key arriving in
`GetItem`:
```
(lldb) break set -n lldb_private::python::PythonDictionary::GetItem
(lldb) run --no-use-colors -b -s /tmp/bp_cmds.txt
* stop reason = breakpoint 1.1
(lldb) up
(lldb) frame variable key.m_py_obj
(PyObject *) key.m_py_obj = nullptr
```
Continuing lands on the dereference of that `NULL` inside CPython:
```
(lldb) continue
* stop reason = EXC_BAD_ACCESS (code=1, address=0x8)
frame #0: PyDict_GetItemWithError + 40
-> ldr x8, [x1, #0x8]
```
`x1` holds the key argument, which is `NULL`, so reading the type field
at offset `0x8` faults at address `0x8`.
`GetItem` already guards against an invalid dictionary (`!IsValid()`);
extend that guard to reject an invalid key as well and return
`nullDeref()`. `GetItemForKey` consumes the error and returns an empty
`PythonObject`, so existing callers such as `ResolveNameWithDictionary`
keep working and the breakpoint command now fails cleanly instead of
crashing.
This was found by `lldb-commandinterpreter-fuzzer`.
Adds `PythonDataObjectsTest.TestPythonDictionaryGetItemWithInvalidKey`,
which feeds an invalid-UTF-8 key to `GetItem`. Without the fix the test
dereferences the `NULL` key and crashes (`SIGSEGV`).
2026-07-06 01:51:36 -08:00
|
|
|
if (!IsValid() || !key.IsValid())
|
2019-10-17 14:22:06 -08:00
|
|
|
return nullDeref();
|
|
|
|
|
PyObject *o = PyDict_GetItemWithError(m_py_obj, key.get());
|
|
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
return exception();
|
|
|
|
|
if (!o)
|
|
|
|
|
return keyError();
|
|
|
|
|
return Retain<PythonObject>(o);
|
|
|
|
|
}
|
|
|
|
|
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
Expected<PythonObject> PythonDictionary::GetItem(const Twine &key) const {
|
2019-10-17 14:22:06 -08:00
|
|
|
if (!IsValid())
|
|
|
|
|
return nullDeref();
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
PyObject *o = PyDict_GetItemString(m_py_obj, NullTerminated(key));
|
2019-10-17 14:22:06 -08:00
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
return exception();
|
|
|
|
|
if (!o)
|
|
|
|
|
return keyError();
|
|
|
|
|
return Retain<PythonObject>(o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Error PythonDictionary::SetItem(const PythonObject &key,
|
|
|
|
|
const PythonObject &value) const {
|
|
|
|
|
if (!IsValid() || !value.IsValid())
|
|
|
|
|
return nullDeref();
|
|
|
|
|
int r = PyDict_SetItem(m_py_obj, key.get(), value.get());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return exception();
|
|
|
|
|
return Error::success();
|
|
|
|
|
}
|
|
|
|
|
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
Error PythonDictionary::SetItem(const Twine &key,
|
2019-10-17 14:22:06 -08:00
|
|
|
const PythonObject &value) const {
|
|
|
|
|
if (!IsValid() || !value.IsValid())
|
|
|
|
|
return nullDeref();
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
int r = PyDict_SetItemString(m_py_obj, NullTerminated(key), value.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
if (r < 0)
|
|
|
|
|
return exception();
|
|
|
|
|
return Error::success();
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
void PythonDictionary::SetItemForKey(const PythonObject &key,
|
|
|
|
|
const PythonObject &value) {
|
2019-10-17 14:22:06 -08:00
|
|
|
Error error = SetItem(key, value);
|
|
|
|
|
if (error)
|
|
|
|
|
llvm::consumeError(std::move(error));
|
2012-08-23 14:02:23 -08:00
|
|
|
}
|
|
|
|
|
|
2015-03-17 12:04:04 -08:00
|
|
|
StructuredData::DictionarySP
|
|
|
|
|
PythonDictionary::CreateStructuredDictionary() const {
|
|
|
|
|
StructuredData::DictionarySP result(new StructuredData::Dictionary);
|
|
|
|
|
PythonList keys(GetKeys());
|
|
|
|
|
uint32_t num_keys = keys.GetSize();
|
|
|
|
|
for (uint32_t i = 0; i < num_keys; ++i) {
|
|
|
|
|
PythonObject key = keys.GetItemAtIndex(i);
|
|
|
|
|
PythonObject value = GetItemForKey(key);
|
|
|
|
|
StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
|
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
llvm-svn: 250195
2015-10-13 10:16:15 -08:00
|
|
|
result->AddItem(key.Str().GetString(), structured_value);
|
2015-03-17 12:04:04 -08:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 19:14:44 -08:00
|
|
|
PythonModule PythonModule::BuiltinsModule() { return AddModule("builtins"); }
|
2015-11-11 10:42:27 -09:00
|
|
|
|
|
|
|
|
PythonModule PythonModule::MainModule() { return AddModule("__main__"); }
|
|
|
|
|
|
|
|
|
|
PythonModule PythonModule::AddModule(llvm::StringRef module) {
|
|
|
|
|
std::string str = module.str();
|
|
|
|
|
return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
|
2015-11-11 08:59:49 -09:00
|
|
|
}
|
|
|
|
|
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
Expected<PythonModule> PythonModule::Import(const Twine &name) {
|
|
|
|
|
PyObject *mod = PyImport_ImportModule(NullTerminated(name));
|
2019-10-08 09:56:18 -08:00
|
|
|
if (!mod)
|
|
|
|
|
return exception();
|
|
|
|
|
return Take<PythonModule>(mod);
|
|
|
|
|
}
|
|
|
|
|
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
Expected<PythonObject> PythonModule::Get(const Twine &name) {
|
2019-10-08 09:56:18 -08:00
|
|
|
if (!IsValid())
|
|
|
|
|
return nullDeref();
|
|
|
|
|
PyObject *dict = PyModule_GetDict(m_py_obj);
|
|
|
|
|
if (!dict)
|
|
|
|
|
return exception();
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
PyObject *item = PyDict_GetItemString(dict, NullTerminated(name));
|
2019-10-08 09:56:18 -08:00
|
|
|
if (!item)
|
|
|
|
|
return exception();
|
|
|
|
|
return Retain<PythonObject>(item);
|
2015-11-13 12:28:45 -09:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
bool PythonModule::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return PyModule_Check(py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonDictionary PythonModule::GetDictionary() const {
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
if (!IsValid())
|
|
|
|
|
return PythonDictionary();
|
|
|
|
|
return Retain<PythonDictionary>(PyModule_GetDict(m_py_obj));
|
2015-11-11 08:59:49 -09:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
bool PythonCallable::Check(PyObject *py_obj) {
|
|
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
2025-12-01 12:12:42 -09:00
|
|
|
PythonObject python_obj(PyRefType::Borrowed, py_obj);
|
|
|
|
|
|
|
|
|
|
// Handle staticmethod/classmethod descriptors by extracting the
|
|
|
|
|
// `__func__` attribute.
|
|
|
|
|
if (python_obj.HasAttribute("__func__")) {
|
|
|
|
|
PythonObject function_obj = python_obj.GetAttributeValue("__func__");
|
|
|
|
|
if (!function_obj.IsAllocated())
|
|
|
|
|
return false;
|
|
|
|
|
return PyCallable_Check(function_obj.release());
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
return PyCallable_Check(py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-17 14:22:06 -08:00
|
|
|
static const char get_arg_info_script[] = R"(
|
|
|
|
|
from inspect import signature, Parameter, ismethod
|
|
|
|
|
from collections import namedtuple
|
2019-11-04 11:48:49 -09:00
|
|
|
ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs'])
|
2019-10-21 18:32:37 -08:00
|
|
|
def main(f):
|
2019-10-17 14:22:06 -08:00
|
|
|
count = 0
|
|
|
|
|
varargs = False
|
|
|
|
|
for parameter in signature(f).parameters.values():
|
|
|
|
|
kind = parameter.kind
|
|
|
|
|
if kind in (Parameter.POSITIONAL_ONLY,
|
|
|
|
|
Parameter.POSITIONAL_OR_KEYWORD):
|
|
|
|
|
count += 1
|
|
|
|
|
elif kind == Parameter.VAR_POSITIONAL:
|
|
|
|
|
varargs = True
|
|
|
|
|
elif kind in (Parameter.KEYWORD_ONLY,
|
|
|
|
|
Parameter.VAR_KEYWORD):
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
raise Exception(f'unknown parameter kind: {kind}')
|
2019-11-04 11:48:49 -09:00
|
|
|
return ArgInfo(count, varargs)
|
2019-10-17 14:22:06 -08:00
|
|
|
)";
|
|
|
|
|
|
[lldb] Reimplement PythonCallable::GetArgInfo without executing Python code (#213378)
`b05a5d0a` added an arity-trimming step to the shared
`ScriptedPythonInterface::Dispatch`: extensions are now allowed to
define methods with trailing parameters as optional
(`num_children(self)` vs. `num_children(self, max_count)`), so before
calling into a method, `Dispatch` needs to know how many positional
arguments it actually accepts and drop any trailing ones we'd otherwise
pass.
That check calls `PythonCallable::GetArgInfo`, which ran a whole
embedded Python script through `inspect.signature` on every call, since
every scripted-extension dispatch goes through it.
For the common case `GetArgInfo()` actually needs to handle fast (plain
Python functions/methods, classes used as constructors, and callable
instances defining `__call__`, i.e. everything `Dispatch<T>()` and
`CreatePluginObject()` ever pass it), the answer is available as plain
data attributes, with no Python bytecode execution required:
`__func__`/`__self__` to unwrap bound methods, and `__code__`'s
`co_argcount`/`co_flags` for the actual positional-argument count and
varargs bit. For a class, that means `__init__` -- except a class may
customize `__new__` instead and leave `__init__` untouched, in which
case `object.__init__` becomes lenient about extra arguments.
Anything else still lacking `__code__` can fall back to the original
`inspect.signature()`-based implementation, now exposed as
`PythonCallable::GetArgInfoFromInspectSignature()` so it can be used
separately.
rdar://183776556
---------
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2026-08-01 15:23:21 -08:00
|
|
|
// inspect.signature() is deeply recursive and expensive in C-stack terms;
|
|
|
|
|
// reentrant scripted callbacks dispatched through GetArgInfo() can turn
|
|
|
|
|
// that into a fatal stack overflow instead of a catchable Python
|
|
|
|
|
// RecursionError. GetArgInfo() never calls this itself; callers fall back
|
|
|
|
|
// to it explicitly when they need to handle callables its cheaper,
|
|
|
|
|
// attribute-only approach can't (e.g. builtins).
|
|
|
|
|
Expected<PythonCallable::ArgInfo>
|
|
|
|
|
PythonCallable::GetArgInfoFromInspectSignature(const PythonCallable &callable) {
|
|
|
|
|
PythonCallable::ArgInfo result = {};
|
2019-10-21 18:32:37 -08:00
|
|
|
// no need to synchronize access to this global, we already have the GIL
|
|
|
|
|
static PythonScript get_arg_info(get_arg_info_script);
|
[lldb] Reimplement PythonCallable::GetArgInfo without executing Python code (#213378)
`b05a5d0a` added an arity-trimming step to the shared
`ScriptedPythonInterface::Dispatch`: extensions are now allowed to
define methods with trailing parameters as optional
(`num_children(self)` vs. `num_children(self, max_count)`), so before
calling into a method, `Dispatch` needs to know how many positional
arguments it actually accepts and drop any trailing ones we'd otherwise
pass.
That check calls `PythonCallable::GetArgInfo`, which ran a whole
embedded Python script through `inspect.signature` on every call, since
every scripted-extension dispatch goes through it.
For the common case `GetArgInfo()` actually needs to handle fast (plain
Python functions/methods, classes used as constructors, and callable
instances defining `__call__`, i.e. everything `Dispatch<T>()` and
`CreatePluginObject()` ever pass it), the answer is available as plain
data attributes, with no Python bytecode execution required:
`__func__`/`__self__` to unwrap bound methods, and `__code__`'s
`co_argcount`/`co_flags` for the actual positional-argument count and
varargs bit. For a class, that means `__init__` -- except a class may
customize `__new__` instead and leave `__init__` untouched, in which
case `object.__init__` becomes lenient about extra arguments.
Anything else still lacking `__code__` can fall back to the original
`inspect.signature()`-based implementation, now exposed as
`PythonCallable::GetArgInfoFromInspectSignature()` so it can be used
separately.
rdar://183776556
---------
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2026-08-01 15:23:21 -08:00
|
|
|
Expected<PythonObject> pyarginfo = get_arg_info(callable);
|
2019-10-17 14:22:06 -08:00
|
|
|
if (!pyarginfo)
|
|
|
|
|
return pyarginfo.takeError();
|
2019-11-04 11:48:49 -09:00
|
|
|
long long count =
|
|
|
|
|
cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));
|
|
|
|
|
bool has_varargs =
|
2019-10-17 14:22:06 -08:00
|
|
|
cantFail(As<bool>(pyarginfo.get().GetAttribute("has_varargs")));
|
[lldb] Reimplement PythonCallable::GetArgInfo without executing Python code (#213378)
`b05a5d0a` added an arity-trimming step to the shared
`ScriptedPythonInterface::Dispatch`: extensions are now allowed to
define methods with trailing parameters as optional
(`num_children(self)` vs. `num_children(self, max_count)`), so before
calling into a method, `Dispatch` needs to know how many positional
arguments it actually accepts and drop any trailing ones we'd otherwise
pass.
That check calls `PythonCallable::GetArgInfo`, which ran a whole
embedded Python script through `inspect.signature` on every call, since
every scripted-extension dispatch goes through it.
For the common case `GetArgInfo()` actually needs to handle fast (plain
Python functions/methods, classes used as constructors, and callable
instances defining `__call__`, i.e. everything `Dispatch<T>()` and
`CreatePluginObject()` ever pass it), the answer is available as plain
data attributes, with no Python bytecode execution required:
`__func__`/`__self__` to unwrap bound methods, and `__code__`'s
`co_argcount`/`co_flags` for the actual positional-argument count and
varargs bit. For a class, that means `__init__` -- except a class may
customize `__new__` instead and leave `__init__` untouched, in which
case `object.__init__` becomes lenient about extra arguments.
Anything else still lacking `__code__` can fall back to the original
`inspect.signature()`-based implementation, now exposed as
`PythonCallable::GetArgInfoFromInspectSignature()` so it can be used
separately.
rdar://183776556
---------
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2026-08-01 15:23:21 -08:00
|
|
|
result.max_positional_args =
|
|
|
|
|
has_varargs ? PythonCallable::ArgInfo::UNBOUNDED : count;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2019-10-17 14:22:06 -08:00
|
|
|
|
[lldb] Reimplement PythonCallable::GetArgInfo without executing Python code (#213378)
`b05a5d0a` added an arity-trimming step to the shared
`ScriptedPythonInterface::Dispatch`: extensions are now allowed to
define methods with trailing parameters as optional
(`num_children(self)` vs. `num_children(self, max_count)`), so before
calling into a method, `Dispatch` needs to know how many positional
arguments it actually accepts and drop any trailing ones we'd otherwise
pass.
That check calls `PythonCallable::GetArgInfo`, which ran a whole
embedded Python script through `inspect.signature` on every call, since
every scripted-extension dispatch goes through it.
For the common case `GetArgInfo()` actually needs to handle fast (plain
Python functions/methods, classes used as constructors, and callable
instances defining `__call__`, i.e. everything `Dispatch<T>()` and
`CreatePluginObject()` ever pass it), the answer is available as plain
data attributes, with no Python bytecode execution required:
`__func__`/`__self__` to unwrap bound methods, and `__code__`'s
`co_argcount`/`co_flags` for the actual positional-argument count and
varargs bit. For a class, that means `__init__` -- except a class may
customize `__new__` instead and leave `__init__` untouched, in which
case `object.__init__` becomes lenient about extra arguments.
Anything else still lacking `__code__` can fall back to the original
`inspect.signature()`-based implementation, now exposed as
`PythonCallable::GetArgInfoFromInspectSignature()` so it can be used
separately.
rdar://183776556
---------
Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2026-08-01 15:23:21 -08:00
|
|
|
// GetArgInfo()'s branches, top to bottom (`func` is what each branch ends up
|
|
|
|
|
// introspecting; the final step is always func.__code__.co_argcount/co_flags):
|
|
|
|
|
//
|
|
|
|
|
// callable
|
|
|
|
|
// |-- has __self__ -> func = __func__ (bound method;
|
|
|
|
|
// | fails for slot wrappers, e.g. (1).__add__)
|
|
|
|
|
// |-- has __code__ already -> func = callable (plain function)
|
|
|
|
|
// `-- neither
|
|
|
|
|
// |-- is a class
|
|
|
|
|
// | |-- __init__ has __code__ -> func = __init__
|
|
|
|
|
// | `-- else: check __new__ too (object.__init__ is lenient about
|
|
|
|
|
// | extra args once __new__ is overridden)
|
|
|
|
|
// | |-- __new__ has __code__ -> func = __new__
|
|
|
|
|
// | `-- else -> ArgInfo{0} (object's defaults)
|
|
|
|
|
// `-- is an instance
|
|
|
|
|
// `-- func = __call__ (unwrap __func__ if bound)
|
|
|
|
|
// `-- no __code__ -> error (e.g. a builtin)
|
|
|
|
|
Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return nullDeref();
|
|
|
|
|
|
|
|
|
|
PythonObject func = *this;
|
|
|
|
|
bool implicit_first_arg = false;
|
|
|
|
|
if (HasAttribute("__self__")) {
|
|
|
|
|
implicit_first_arg = true;
|
|
|
|
|
Expected<PythonObject> func_or_err = GetAttribute("__func__");
|
|
|
|
|
if (!func_or_err)
|
|
|
|
|
return func_or_err.takeError();
|
|
|
|
|
func = *func_or_err;
|
|
|
|
|
} else if (!HasAttribute("__code__")) {
|
|
|
|
|
implicit_first_arg = true;
|
|
|
|
|
if (PyType_Check(m_py_obj)) {
|
|
|
|
|
Expected<PythonObject> init_or_err = GetAttribute("__init__");
|
|
|
|
|
if (!init_or_err)
|
|
|
|
|
return init_or_err.takeError();
|
|
|
|
|
func = *init_or_err;
|
|
|
|
|
if (!func.HasAttribute("__code__")) {
|
|
|
|
|
// __init__ is still object.__init__. A class may customize
|
|
|
|
|
// __new__ instead and leave __init__ untouched, which makes
|
|
|
|
|
// object.__init__ lenient about extra arguments -- so check
|
|
|
|
|
// __new__ too before concluding there are none.
|
|
|
|
|
Expected<PythonObject> new_or_err = GetAttribute("__new__");
|
|
|
|
|
if (!new_or_err)
|
|
|
|
|
return new_or_err.takeError();
|
|
|
|
|
func = *new_or_err;
|
|
|
|
|
if (!func.HasAttribute("__code__"))
|
|
|
|
|
return ArgInfo{0};
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Expected<PythonObject> call_or_err = GetAttribute("__call__");
|
|
|
|
|
if (!call_or_err)
|
|
|
|
|
return call_or_err.takeError();
|
|
|
|
|
func = *call_or_err;
|
|
|
|
|
if (func.HasAttribute("__self__")) {
|
|
|
|
|
Expected<PythonObject> inner_or_err = func.GetAttribute("__func__");
|
|
|
|
|
if (!inner_or_err)
|
|
|
|
|
return inner_or_err.takeError();
|
|
|
|
|
func = *inner_or_err;
|
|
|
|
|
}
|
|
|
|
|
if (!func.HasAttribute("__code__"))
|
|
|
|
|
return llvm::createStringError("__call__ has no __code__");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expected<PythonObject> code_or_err = func.GetAttribute("__code__");
|
|
|
|
|
if (!code_or_err)
|
|
|
|
|
return code_or_err.takeError();
|
|
|
|
|
PythonObject code = *code_or_err;
|
|
|
|
|
|
|
|
|
|
Expected<long long> argcount =
|
|
|
|
|
As<long long>(code.GetAttribute("co_argcount"));
|
|
|
|
|
if (!argcount)
|
|
|
|
|
return argcount.takeError();
|
|
|
|
|
Expected<long long> flags = As<long long>(code.GetAttribute("co_flags"));
|
|
|
|
|
if (!flags)
|
|
|
|
|
return flags.takeError();
|
|
|
|
|
|
|
|
|
|
ArgInfo result = {};
|
|
|
|
|
// Mirrors CPython's CO_VARARGS from <code.h>, which isn't reliably
|
|
|
|
|
// visible across the Python versions/platforms this file builds against.
|
|
|
|
|
constexpr long long kCoFlagVarArgs = 0x04;
|
|
|
|
|
if (*flags & kCoFlagVarArgs) {
|
|
|
|
|
result.max_positional_args = ArgInfo::UNBOUNDED;
|
|
|
|
|
} else {
|
|
|
|
|
long long count = *argcount - (implicit_first_arg ? 1 : 0);
|
|
|
|
|
result.max_positional_args = count > 0 ? static_cast<unsigned>(count) : 0;
|
|
|
|
|
}
|
2015-11-12 07:23:16 -09:00
|
|
|
return result;
|
2015-11-11 10:42:27 -09:00
|
|
|
}
|
|
|
|
|
|
2019-10-18 23:05:33 -08:00
|
|
|
constexpr unsigned
|
|
|
|
|
PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject PythonCallable::operator()() {
|
|
|
|
|
return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-01 14:27:14 -08:00
|
|
|
PythonObject
|
|
|
|
|
PythonCallable::operator()(std::initializer_list<PyObject *> args) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonTuple arg_tuple(args);
|
|
|
|
|
return PythonObject(PyRefType::Owned,
|
|
|
|
|
PyObject_CallObject(m_py_obj, arg_tuple.get()));
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-01 14:27:14 -08:00
|
|
|
PythonObject
|
|
|
|
|
PythonCallable::operator()(std::initializer_list<PythonObject> args) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonTuple arg_tuple(args);
|
2015-10-20 09:38:49 -08:00
|
|
|
return PythonObject(PyRefType::Owned,
|
2015-11-11 10:42:27 -09:00
|
|
|
PyObject_CallObject(m_py_obj, arg_tuple.get()));
|
2015-10-20 09:38:49 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-15 11:35:48 -08:00
|
|
|
bool PythonFile::Check(PyObject *py_obj) {
|
2019-10-02 20:04:48 -08:00
|
|
|
if (!py_obj)
|
|
|
|
|
return false;
|
2015-10-15 11:35:48 -08:00
|
|
|
// In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a
|
|
|
|
|
// first-class object type anymore. `PyFile_FromFd` is just a thin wrapper
|
2018-04-30 08:49:04 -08:00
|
|
|
// over `io.open()`, which returns some object derived from `io.IOBase`. As a
|
|
|
|
|
// result, the only way to detect a file in Python 3 is to check whether it
|
2019-10-09 12:56:17 -08:00
|
|
|
// inherits from `io.IOBase`.
|
|
|
|
|
auto io_module = PythonModule::Import("io");
|
|
|
|
|
if (!io_module) {
|
|
|
|
|
llvm::consumeError(io_module.takeError());
|
2015-10-15 11:35:48 -08:00
|
|
|
return false;
|
2019-10-09 12:56:17 -08:00
|
|
|
}
|
|
|
|
|
auto iobase = io_module.get().Get("IOBase");
|
|
|
|
|
if (!iobase) {
|
|
|
|
|
llvm::consumeError(iobase.takeError());
|
2015-10-15 11:35:48 -08:00
|
|
|
return false;
|
2019-10-09 12:56:17 -08:00
|
|
|
}
|
|
|
|
|
int r = PyObject_IsInstance(py_obj, iobase.get().get());
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
llvm::consumeError(exception()); // clear the exception and log it.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return !!r;
|
2015-10-15 11:35:48 -08:00
|
|
|
}
|
|
|
|
|
|
2019-10-08 09:56:18 -08:00
|
|
|
const char *PythonException::toCString() const {
|
|
|
|
|
if (!m_repr_bytes)
|
|
|
|
|
return "unknown exception";
|
2025-08-01 06:57:34 -08:00
|
|
|
return PyBytes_AsString(m_repr_bytes);
|
2019-10-08 09:56:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonException::PythonException(const char *caller) {
|
|
|
|
|
assert(PyErr_Occurred());
|
2022-08-27 20:21:07 -08:00
|
|
|
m_exception_type = m_exception = m_traceback = m_repr_bytes = nullptr;
|
2019-10-08 09:56:18 -08:00
|
|
|
PyErr_Fetch(&m_exception_type, &m_exception, &m_traceback);
|
|
|
|
|
PyErr_NormalizeException(&m_exception_type, &m_exception, &m_traceback);
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
if (m_exception) {
|
|
|
|
|
PyObject *repr = PyObject_Repr(m_exception);
|
|
|
|
|
if (repr) {
|
|
|
|
|
m_repr_bytes = PyUnicode_AsEncodedString(repr, "utf-8", nullptr);
|
|
|
|
|
if (!m_repr_bytes) {
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
}
|
|
|
|
|
Py_XDECREF(repr);
|
|
|
|
|
} else {
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-31 05:57:48 -09:00
|
|
|
Log *log = GetLog(LLDBLog::Script);
|
2019-10-08 09:56:18 -08:00
|
|
|
if (caller)
|
|
|
|
|
LLDB_LOGF(log, "%s failed with exception: %s", caller, toCString());
|
|
|
|
|
else
|
|
|
|
|
LLDB_LOGF(log, "python exception: %s", toCString());
|
|
|
|
|
}
|
|
|
|
|
void PythonException::Restore() {
|
|
|
|
|
if (m_exception_type && m_exception) {
|
|
|
|
|
PyErr_Restore(m_exception_type, m_exception, m_traceback);
|
|
|
|
|
} else {
|
|
|
|
|
PyErr_SetString(PyExc_Exception, toCString());
|
|
|
|
|
}
|
2022-08-27 20:21:07 -08:00
|
|
|
m_exception_type = m_exception = m_traceback = nullptr;
|
2019-10-08 09:56:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PythonException::~PythonException() {
|
2024-09-18 13:54:49 -08:00
|
|
|
Py_XDECREF(m_exception_type);
|
2024-09-18 16:27:44 -08:00
|
|
|
Py_XDECREF(m_exception);
|
2019-10-08 09:56:18 -08:00
|
|
|
Py_XDECREF(m_traceback);
|
|
|
|
|
Py_XDECREF(m_repr_bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PythonException::log(llvm::raw_ostream &OS) const { OS << toCString(); }
|
|
|
|
|
|
|
|
|
|
std::error_code PythonException::convertToErrorCode() const {
|
|
|
|
|
return llvm::inconvertibleErrorCode();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 18:32:37 -08:00
|
|
|
bool PythonException::Matches(PyObject *exc) const {
|
|
|
|
|
return PyErr_GivenExceptionMatches(m_exception_type, exc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char read_exception_script[] = R"(
|
|
|
|
|
import sys
|
|
|
|
|
from traceback import print_exception
|
|
|
|
|
if sys.version_info.major < 3:
|
|
|
|
|
from StringIO import StringIO
|
|
|
|
|
else:
|
|
|
|
|
from io import StringIO
|
|
|
|
|
def main(exc_type, exc_value, tb):
|
|
|
|
|
f = StringIO()
|
|
|
|
|
print_exception(exc_type, exc_value, tb, file=f)
|
|
|
|
|
return f.getvalue()
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
std::string PythonException::ReadBacktrace() const {
|
|
|
|
|
|
|
|
|
|
if (!m_traceback)
|
|
|
|
|
return toCString();
|
|
|
|
|
|
|
|
|
|
// no need to synchronize access to this global, we already have the GIL
|
|
|
|
|
static PythonScript read_exception(read_exception_script);
|
|
|
|
|
|
|
|
|
|
Expected<std::string> backtrace = As<std::string>(
|
|
|
|
|
read_exception(m_exception_type, m_exception, m_traceback));
|
|
|
|
|
|
|
|
|
|
if (!backtrace) {
|
|
|
|
|
std::string message =
|
|
|
|
|
std::string(toCString()) + "\n" +
|
2020-04-06 08:06:02 -08:00
|
|
|
"Traceback unavailable, an error occurred while reading it:\n";
|
2019-10-21 18:32:37 -08:00
|
|
|
return (message + llvm::toString(backtrace.takeError()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::move(backtrace.get());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-08 09:56:18 -08:00
|
|
|
char PythonException::ID = 0;
|
|
|
|
|
|
2019-10-14 12:15:34 -08:00
|
|
|
llvm::Expected<File::OpenOptions>
|
|
|
|
|
GetOptionsForPyObject(const PythonObject &obj) {
|
|
|
|
|
auto options = File::OpenOptions(0);
|
2019-10-09 12:56:17 -08:00
|
|
|
auto readable = As<bool>(obj.CallMethod("readable"));
|
|
|
|
|
if (!readable)
|
|
|
|
|
return readable.takeError();
|
|
|
|
|
auto writable = As<bool>(obj.CallMethod("writable"));
|
|
|
|
|
if (!writable)
|
|
|
|
|
return writable.takeError();
|
2021-07-28 10:07:03 -08:00
|
|
|
if (readable.get() && writable.get())
|
|
|
|
|
options |= File::eOpenOptionReadWrite;
|
|
|
|
|
else if (writable.get())
|
|
|
|
|
options |= File::eOpenOptionWriteOnly;
|
|
|
|
|
else if (readable.get())
|
|
|
|
|
options |= File::eOpenOptionReadOnly;
|
2019-10-14 12:15:34 -08:00
|
|
|
return options;
|
2019-10-09 12:56:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Base class template for python files. All it knows how to do
|
|
|
|
|
// is hold a reference to the python object and close or flush it
|
|
|
|
|
// when the File is closed.
|
|
|
|
|
namespace {
|
|
|
|
|
template <typename Base> class OwnedPythonFile : public Base {
|
|
|
|
|
public:
|
|
|
|
|
template <typename... Args>
|
|
|
|
|
OwnedPythonFile(const PythonFile &file, bool borrowed, Args... args)
|
|
|
|
|
: Base(args...), m_py_obj(file), m_borrowed(borrowed) {
|
|
|
|
|
assert(m_py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~OwnedPythonFile() override {
|
|
|
|
|
assert(m_py_obj);
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
Close();
|
eliminate nontrivial Reset(...) from TypedPythonObject
Summary:
This deletes `Reset(...)`, except for the no-argument form `Reset()`
from `TypedPythonObject`, and therefore from `PythonString`, `PythonList`,
etc.
It updates the various callers to use assignment, `As<>`, `Take<>`,
and `Retain<>`, as appropriate.
followon to https://reviews.llvm.org/D69080
Reviewers: JDevlieghere, clayborg, labath, jingham
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D69133
llvm-svn: 375350
2019-10-19 10:43:49 -08:00
|
|
|
// we need to ensure the python object is released while we still
|
|
|
|
|
// hold the GIL
|
2019-10-09 12:56:17 -08:00
|
|
|
m_py_obj.Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsPythonSideValid() const {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
auto closed = As<bool>(m_py_obj.GetAttribute("closed"));
|
|
|
|
|
if (!closed) {
|
|
|
|
|
llvm::consumeError(closed.takeError());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return !closed.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsValid() const override {
|
|
|
|
|
return IsPythonSideValid() && Base::IsValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status Close() override {
|
|
|
|
|
assert(m_py_obj);
|
|
|
|
|
Status py_error, base_error;
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
if (!m_borrowed) {
|
|
|
|
|
auto r = m_py_obj.CallMethod("close");
|
|
|
|
|
if (!r)
|
2024-09-05 11:19:31 -08:00
|
|
|
py_error = Status::FromError(r.takeError());
|
2019-10-09 12:56:17 -08:00
|
|
|
}
|
|
|
|
|
base_error = Base::Close();
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
2019-10-09 12:56:17 -08:00
|
|
|
if (py_error.Fail())
|
2024-09-18 13:54:49 -08:00
|
|
|
return py_error.Clone();
|
|
|
|
|
return base_error.Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
};
|
|
|
|
|
|
2019-10-15 08:46:27 -08:00
|
|
|
PyObject *GetPythonObject() const {
|
|
|
|
|
assert(m_py_obj.IsValid());
|
|
|
|
|
return m_py_obj.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool classof(const File *file) = delete;
|
|
|
|
|
|
2019-10-09 12:56:17 -08:00
|
|
|
protected:
|
|
|
|
|
PythonFile m_py_obj;
|
|
|
|
|
bool m_borrowed;
|
|
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
// A SimplePythonFile is a OwnedPythonFile that just does all I/O as
|
|
|
|
|
// a NativeFile
|
|
|
|
|
namespace {
|
|
|
|
|
class SimplePythonFile : public OwnedPythonFile<NativeFile> {
|
|
|
|
|
public:
|
|
|
|
|
SimplePythonFile(const PythonFile &file, bool borrowed, int fd,
|
2019-10-14 12:15:34 -08:00
|
|
|
File::OpenOptions options)
|
2019-10-09 12:56:17 -08:00
|
|
|
: OwnedPythonFile(file, borrowed, fd, options, false) {}
|
2019-10-15 08:46:27 -08:00
|
|
|
|
|
|
|
|
static char ID;
|
|
|
|
|
bool isA(const void *classID) const override {
|
|
|
|
|
return classID == &ID || NativeFile::isA(classID);
|
|
|
|
|
}
|
|
|
|
|
static bool classof(const File *file) { return file->isA(&ID); }
|
2019-10-09 12:56:17 -08:00
|
|
|
};
|
2019-10-15 08:46:27 -08:00
|
|
|
char SimplePythonFile::ID = 0;
|
2019-10-09 12:56:17 -08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
// Shared methods between TextPythonFile and BinaryPythonFile
|
|
|
|
|
namespace {
|
|
|
|
|
class PythonIOFile : public OwnedPythonFile<File> {
|
|
|
|
|
public:
|
|
|
|
|
PythonIOFile(const PythonFile &file, bool borrowed)
|
|
|
|
|
: OwnedPythonFile(file, borrowed) {}
|
|
|
|
|
|
|
|
|
|
~PythonIOFile() override { Close(); }
|
|
|
|
|
|
|
|
|
|
bool IsValid() const override { return IsPythonSideValid(); }
|
|
|
|
|
|
|
|
|
|
Status Close() override {
|
|
|
|
|
assert(m_py_obj);
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
if (m_borrowed)
|
|
|
|
|
return Flush();
|
|
|
|
|
auto r = m_py_obj.CallMethod("close");
|
|
|
|
|
if (!r)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(r.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status Flush() override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
auto r = m_py_obj.CallMethod("flush");
|
|
|
|
|
if (!r)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(r.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-15 08:46:27 -08:00
|
|
|
Expected<File::OpenOptions> GetOptions() const override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
return GetOptionsForPyObject(m_py_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char ID;
|
|
|
|
|
bool isA(const void *classID) const override {
|
|
|
|
|
return classID == &ID || File::isA(classID);
|
|
|
|
|
}
|
|
|
|
|
static bool classof(const File *file) { return file->isA(&ID); }
|
2019-10-09 12:56:17 -08:00
|
|
|
};
|
2019-10-15 08:46:27 -08:00
|
|
|
char PythonIOFile::ID = 0;
|
2019-10-09 12:56:17 -08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
class BinaryPythonFile : public PythonIOFile {
|
|
|
|
|
protected:
|
|
|
|
|
int m_descriptor;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
BinaryPythonFile(int fd, const PythonFile &file, bool borrowed)
|
|
|
|
|
: PythonIOFile(file, borrowed),
|
|
|
|
|
m_descriptor(File::DescriptorIsValid(fd) ? fd
|
|
|
|
|
: File::kInvalidDescriptor) {}
|
|
|
|
|
|
|
|
|
|
int GetDescriptor() const override { return m_descriptor; }
|
|
|
|
|
|
|
|
|
|
Status Write(const void *buf, size_t &num_bytes) override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
PyObject *pybuffer_p = PyMemoryView_FromMemory(
|
|
|
|
|
const_cast<char *>((const char *)buf), num_bytes, PyBUF_READ);
|
|
|
|
|
if (!pybuffer_p)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(llvm::make_error<PythonException>()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
auto pybuffer = Take<PythonObject>(pybuffer_p);
|
|
|
|
|
num_bytes = 0;
|
|
|
|
|
auto bytes_written = As<long long>(m_py_obj.CallMethod("write", pybuffer));
|
|
|
|
|
if (!bytes_written)
|
2024-09-05 11:19:31 -08:00
|
|
|
return Status::FromError(bytes_written.takeError());
|
2019-10-09 12:56:17 -08:00
|
|
|
if (bytes_written.get() < 0)
|
2024-08-27 09:59:31 -08:00
|
|
|
return Status::FromErrorString(
|
|
|
|
|
".write() method returned a negative number!");
|
2019-10-09 12:56:17 -08:00
|
|
|
static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
|
|
|
|
|
num_bytes = bytes_written.get();
|
|
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status Read(void *buf, size_t &num_bytes) override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
|
|
|
|
|
auto pybuffer_obj =
|
|
|
|
|
m_py_obj.CallMethod("read", (unsigned long long)num_bytes);
|
|
|
|
|
if (!pybuffer_obj)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(pybuffer_obj.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
num_bytes = 0;
|
|
|
|
|
if (pybuffer_obj.get().IsNone()) {
|
|
|
|
|
// EOF
|
|
|
|
|
num_bytes = 0;
|
|
|
|
|
return Status();
|
|
|
|
|
}
|
2025-08-05 09:58:59 -08:00
|
|
|
PythonBytes pybytes(PyRefType::Borrowed, pybuffer_obj->get());
|
|
|
|
|
if (!pybytes)
|
|
|
|
|
return Status::FromError(llvm::make_error<PythonException>());
|
|
|
|
|
llvm::ArrayRef<uint8_t> bytes = pybytes.GetBytes();
|
|
|
|
|
memcpy(buf, bytes.begin(), bytes.size());
|
|
|
|
|
num_bytes = bytes.size();
|
2019-10-09 12:56:17 -08:00
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
class TextPythonFile : public PythonIOFile {
|
|
|
|
|
protected:
|
|
|
|
|
int m_descriptor;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
TextPythonFile(int fd, const PythonFile &file, bool borrowed)
|
|
|
|
|
: PythonIOFile(file, borrowed),
|
|
|
|
|
m_descriptor(File::DescriptorIsValid(fd) ? fd
|
|
|
|
|
: File::kInvalidDescriptor) {}
|
|
|
|
|
|
|
|
|
|
int GetDescriptor() const override { return m_descriptor; }
|
|
|
|
|
|
|
|
|
|
Status Write(const void *buf, size_t &num_bytes) override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
auto pystring =
|
|
|
|
|
PythonString::FromUTF8(llvm::StringRef((const char *)buf, num_bytes));
|
|
|
|
|
if (!pystring)
|
2024-09-05 11:19:31 -08:00
|
|
|
return Status::FromError(pystring.takeError());
|
2019-10-09 12:56:17 -08:00
|
|
|
num_bytes = 0;
|
|
|
|
|
auto bytes_written =
|
|
|
|
|
As<long long>(m_py_obj.CallMethod("write", pystring.get()));
|
|
|
|
|
if (!bytes_written)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(bytes_written.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
if (bytes_written.get() < 0)
|
2024-08-27 09:59:31 -08:00
|
|
|
return Status::FromErrorString(
|
|
|
|
|
".write() method returned a negative number!");
|
2019-10-09 12:56:17 -08:00
|
|
|
static_assert(sizeof(long long) >= sizeof(size_t), "overflow");
|
|
|
|
|
num_bytes = bytes_written.get();
|
|
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status Read(void *buf, size_t &num_bytes) override {
|
|
|
|
|
GIL takeGIL;
|
|
|
|
|
size_t num_chars = num_bytes / 6;
|
|
|
|
|
size_t orig_num_bytes = num_bytes;
|
|
|
|
|
num_bytes = 0;
|
|
|
|
|
if (orig_num_bytes < 6) {
|
2024-08-27 09:59:31 -08:00
|
|
|
return Status::FromErrorString(
|
|
|
|
|
"can't read less than 6 bytes from a utf8 text stream");
|
2019-10-09 12:56:17 -08:00
|
|
|
}
|
|
|
|
|
auto pystring = As<PythonString>(
|
|
|
|
|
m_py_obj.CallMethod("read", (unsigned long long)num_chars));
|
|
|
|
|
if (!pystring)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(pystring.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
if (pystring.get().IsNone()) {
|
|
|
|
|
// EOF
|
|
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
auto stringref = pystring.get().AsUTF8();
|
|
|
|
|
if (!stringref)
|
2024-09-18 13:54:49 -08:00
|
|
|
// Cloning since the wrapped exception may still reference the PyThread.
|
|
|
|
|
return Status::FromError(stringref.takeError()).Clone();
|
2019-10-09 12:56:17 -08:00
|
|
|
num_bytes = stringref.get().size();
|
|
|
|
|
memcpy(buf, stringref.get().begin(), num_bytes);
|
|
|
|
|
return Status();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) {
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"invalid PythonFile");
|
|
|
|
|
|
|
|
|
|
int fd = PyObject_AsFileDescriptor(m_py_obj);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
return ConvertToFileForcingUseOfScriptingIOMethods(borrowed);
|
|
|
|
|
}
|
|
|
|
|
auto options = GetOptionsForPyObject(*this);
|
|
|
|
|
if (!options)
|
|
|
|
|
return options.takeError();
|
|
|
|
|
|
2021-07-28 10:07:03 -08:00
|
|
|
File::OpenOptions rw =
|
|
|
|
|
options.get() & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
|
|
|
|
|
File::eOpenOptionReadWrite);
|
|
|
|
|
if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {
|
2019-10-23 05:17:25 -08:00
|
|
|
// LLDB and python will not share I/O buffers. We should probably
|
|
|
|
|
// flush the python buffers now.
|
|
|
|
|
auto r = CallMethod("flush");
|
|
|
|
|
if (!r)
|
|
|
|
|
return r.takeError();
|
|
|
|
|
}
|
2019-10-09 12:56:17 -08:00
|
|
|
|
|
|
|
|
FileSP file_sp;
|
|
|
|
|
if (borrowed) {
|
2023-09-01 20:32:24 -08:00
|
|
|
// In this case we don't need to retain the python
|
2019-10-09 12:56:17 -08:00
|
|
|
// object at all.
|
|
|
|
|
file_sp = std::make_shared<NativeFile>(fd, options.get(), false);
|
|
|
|
|
} else {
|
|
|
|
|
file_sp = std::static_pointer_cast<File>(
|
|
|
|
|
std::make_shared<SimplePythonFile>(*this, borrowed, fd, options.get()));
|
|
|
|
|
}
|
|
|
|
|
if (!file_sp->IsValid())
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"invalid File");
|
|
|
|
|
|
|
|
|
|
return file_sp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Expected<FileSP>
|
|
|
|
|
PythonFile::ConvertToFileForcingUseOfScriptingIOMethods(bool borrowed) {
|
|
|
|
|
|
|
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
|
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"invalid PythonFile");
|
|
|
|
|
|
|
|
|
|
int fd = PyObject_AsFileDescriptor(m_py_obj);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
fd = File::kInvalidDescriptor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto io_module = PythonModule::Import("io");
|
|
|
|
|
if (!io_module)
|
|
|
|
|
return io_module.takeError();
|
|
|
|
|
auto textIOBase = io_module.get().Get("TextIOBase");
|
|
|
|
|
if (!textIOBase)
|
|
|
|
|
return textIOBase.takeError();
|
|
|
|
|
auto rawIOBase = io_module.get().Get("RawIOBase");
|
|
|
|
|
if (!rawIOBase)
|
|
|
|
|
return rawIOBase.takeError();
|
|
|
|
|
auto bufferedIOBase = io_module.get().Get("BufferedIOBase");
|
|
|
|
|
if (!bufferedIOBase)
|
|
|
|
|
return bufferedIOBase.takeError();
|
|
|
|
|
|
|
|
|
|
FileSP file_sp;
|
|
|
|
|
|
|
|
|
|
auto isTextIO = IsInstance(textIOBase.get());
|
|
|
|
|
if (!isTextIO)
|
|
|
|
|
return isTextIO.takeError();
|
|
|
|
|
if (isTextIO.get())
|
|
|
|
|
file_sp = std::static_pointer_cast<File>(
|
|
|
|
|
std::make_shared<TextPythonFile>(fd, *this, borrowed));
|
|
|
|
|
|
|
|
|
|
auto isRawIO = IsInstance(rawIOBase.get());
|
|
|
|
|
if (!isRawIO)
|
|
|
|
|
return isRawIO.takeError();
|
|
|
|
|
auto isBufferedIO = IsInstance(bufferedIOBase.get());
|
|
|
|
|
if (!isBufferedIO)
|
|
|
|
|
return isBufferedIO.takeError();
|
|
|
|
|
|
|
|
|
|
if (isRawIO.get() || isBufferedIO.get()) {
|
|
|
|
|
file_sp = std::static_pointer_cast<File>(
|
|
|
|
|
std::make_shared<BinaryPythonFile>(fd, *this, borrowed));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!file_sp)
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"python file is neither text nor binary");
|
|
|
|
|
|
|
|
|
|
if (!file_sp->IsValid())
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"invalid File");
|
|
|
|
|
|
|
|
|
|
return file_sp;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-15 08:46:27 -08:00
|
|
|
Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {
|
|
|
|
|
if (!file.IsValid())
|
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
|
"invalid file");
|
|
|
|
|
|
|
|
|
|
if (auto *simple = llvm::dyn_cast<SimplePythonFile>(&file))
|
|
|
|
|
return Retain<PythonFile>(simple->GetPythonObject());
|
|
|
|
|
if (auto *pythonio = llvm::dyn_cast<PythonIOFile>(&file))
|
|
|
|
|
return Retain<PythonFile>(pythonio->GetPythonObject());
|
|
|
|
|
|
|
|
|
|
if (!mode) {
|
|
|
|
|
auto m = file.GetOpenMode();
|
|
|
|
|
if (!m)
|
|
|
|
|
return m.takeError();
|
|
|
|
|
mode = m.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject *file_obj;
|
|
|
|
|
file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr,
|
2019-10-30 08:45:13 -08:00
|
|
|
"ignore", nullptr, /*closefd=*/0);
|
2019-10-15 08:46:27 -08:00
|
|
|
|
|
|
|
|
if (!file_obj)
|
|
|
|
|
return exception();
|
|
|
|
|
|
|
|
|
|
return Take<PythonFile>(file_obj);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 18:32:37 -08:00
|
|
|
Error PythonScript::Init() {
|
|
|
|
|
if (function.IsValid())
|
|
|
|
|
return Error::success();
|
|
|
|
|
|
|
|
|
|
PythonDictionary globals(PyInitialValue::Empty);
|
|
|
|
|
auto builtins = PythonModule::BuiltinsModule();
|
|
|
|
|
if (Error error = globals.SetItem("__builtins__", builtins))
|
|
|
|
|
return error;
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o = RunString(script, Py_file_input, globals.get(), globals.get());
|
2019-10-21 18:32:37 -08:00
|
|
|
if (!o)
|
|
|
|
|
return exception();
|
|
|
|
|
Take<PythonObject>(o);
|
|
|
|
|
auto f = As<PythonCallable>(globals.GetItem("main"));
|
|
|
|
|
if (!f)
|
|
|
|
|
return f.takeError();
|
|
|
|
|
function = std::move(f.get());
|
|
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Expected<PythonObject>
|
|
|
|
|
python::runStringOneLine(const llvm::Twine &string,
|
|
|
|
|
const PythonDictionary &globals,
|
|
|
|
|
const PythonDictionary &locals) {
|
|
|
|
|
if (!globals.IsValid() || !locals.IsValid())
|
|
|
|
|
return nullDeref();
|
|
|
|
|
|
|
|
|
|
PyObject *code =
|
|
|
|
|
Py_CompileString(NullTerminated(string), "<string>", Py_eval_input);
|
|
|
|
|
if (!code) {
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
code =
|
|
|
|
|
Py_CompileString(NullTerminated(string), "<string>", Py_single_input);
|
|
|
|
|
}
|
|
|
|
|
if (!code)
|
|
|
|
|
return exception();
|
|
|
|
|
auto code_ref = Take<PythonObject>(code);
|
|
|
|
|
|
|
|
|
|
PyObject *result = PyEval_EvalCode(code, globals.get(), locals.get());
|
|
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
|
return exception();
|
|
|
|
|
|
|
|
|
|
return Take<PythonObject>(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Expected<PythonObject>
|
|
|
|
|
python::runStringMultiLine(const llvm::Twine &string,
|
|
|
|
|
const PythonDictionary &globals,
|
|
|
|
|
const PythonDictionary &locals) {
|
|
|
|
|
if (!globals.IsValid() || !locals.IsValid())
|
|
|
|
|
return nullDeref();
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *result = RunString(NullTerminated(string), Py_file_input,
|
|
|
|
|
globals.get(), locals.get());
|
2019-10-21 18:32:37 -08:00
|
|
|
if (!result)
|
|
|
|
|
return exception();
|
|
|
|
|
return Take<PythonObject>(result);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-04 08:12:58 -08:00
|
|
|
PyObject *lldb_private::python::RunString(const char *str, int start,
|
|
|
|
|
PyObject *globals, PyObject *locals) {
|
2025-08-01 14:27:14 -08:00
|
|
|
const char *filename = "<string>";
|
|
|
|
|
|
|
|
|
|
// Compile the string into a code object.
|
|
|
|
|
PyObject *code = Py_CompileString(str, filename, start);
|
|
|
|
|
if (!code)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
// Execute the code object.
|
|
|
|
|
PyObject *result = PyEval_EvalCode(code, globals, locals);
|
|
|
|
|
|
|
|
|
|
// Clean up the code object.
|
|
|
|
|
Py_DECREF(code);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2025-08-01 15:18:24 -08:00
|
|
|
|
2025-08-04 08:12:58 -08:00
|
|
|
int lldb_private::python::RunSimpleString(const char *str) {
|
2025-08-01 15:18:24 -08:00
|
|
|
PyObject *main_module = PyImport_AddModule("__main__");
|
|
|
|
|
if (!main_module)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
PyObject *globals = PyModule_GetDict(main_module);
|
|
|
|
|
if (!globals)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
PyObject *result = RunString(str, Py_file_input, globals, globals);
|
|
|
|
|
if (!result)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|