[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
|
|
|
//===-- PythonDataObjectsTests.cpp ----------------------------------------===//
|
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
|
|
|
//
|
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
|
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
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2016-08-11 07:31:30 -08:00
|
|
|
#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
|
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
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
|
|
#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
|
|
|
|
|
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
|
2024-02-21 21:59:03 -09:00
|
|
|
#include "TestingSupport/SubsystemRAII.h"
|
2015-10-15 11:35:48 -08:00
|
|
|
#include "lldb/Host/File.h"
|
|
|
|
|
#include "lldb/Host/FileSystem.h"
|
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
|
|
|
#include "lldb/Host/HostInfo.h"
|
2017-05-29 00:25:46 -08:00
|
|
|
#include "lldb/lldb-enumerations.h"
|
2019-09-26 09:54:59 -08:00
|
|
|
#include "llvm/Testing/Support/Error.h"
|
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
|
|
|
|
2015-11-12 16:24:35 -09:00
|
|
|
#include "PythonTestSuite.h"
|
|
|
|
|
|
2023-05-22 12:52:09 -08:00
|
|
|
#include <variant>
|
|
|
|
|
|
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
|
|
|
using namespace lldb_private;
|
2019-10-17 14:22:06 -08:00
|
|
|
using namespace lldb_private::python;
|
2019-10-21 18:32:37 -08:00
|
|
|
using llvm::Expected;
|
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
|
|
|
|
2015-11-12 16:24:35 -09:00
|
|
|
class PythonDataObjectsTest : public PythonTestSuite {
|
2024-02-21 21:59:03 -09:00
|
|
|
SubsystemRAII<FileSystem> subsystems;
|
|
|
|
|
|
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
|
|
|
public:
|
|
|
|
|
void SetUp() override {
|
2015-11-12 16:24:35 -09:00
|
|
|
PythonTestSuite::SetUp();
|
2016-09-06 12:57:50 -08: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
|
|
|
m_sys_module = unwrapIgnoringErrors(PythonModule::Import("sys"));
|
2015-11-11 10:42:27 -09:00
|
|
|
m_main_module = PythonModule::MainModule();
|
|
|
|
|
m_builtins_module = PythonModule::BuiltinsModule();
|
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
|
|
|
}
|
2016-09-06 12:57:50 -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
|
|
|
void TearDown() override {
|
2015-11-11 10:42:27 -09:00
|
|
|
m_sys_module.Reset();
|
|
|
|
|
m_main_module.Reset();
|
|
|
|
|
m_builtins_module.Reset();
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-12 16:24:35 -09:00
|
|
|
PythonTestSuite::TearDown();
|
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
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
protected:
|
|
|
|
|
PythonModule m_sys_module;
|
|
|
|
|
PythonModule m_main_module;
|
|
|
|
|
PythonModule m_builtins_module;
|
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
|
|
|
};
|
|
|
|
|
|
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
|
|
|
TEST_F(PythonDataObjectsTest, TestOwnedReferences) {
|
2015-10-14 13:06:13 -08:00
|
|
|
// After creating a new object, the refcount should be >= 1
|
2024-02-17 10:37:26 -09:00
|
|
|
PyObject *obj = PyBytes_FromString("foo");
|
|
|
|
|
Py_ssize_t original_refcnt = Py_REFCNT(obj);
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_LE(1, original_refcnt);
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// If we take an owned reference, the refcount should be the same
|
2024-02-17 10:37:26 -09:00
|
|
|
PythonObject owned(PyRefType::Owned, obj);
|
|
|
|
|
Py_ssize_t owned_refcnt = Py_REFCNT(owned.get());
|
|
|
|
|
EXPECT_EQ(original_refcnt, owned_refcnt);
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Take another reference and verify that the refcount increases by 1
|
2024-02-17 10:37:26 -09:00
|
|
|
PythonObject strong_ref(owned);
|
|
|
|
|
Py_ssize_t strong_refcnt = Py_REFCNT(strong_ref.get());
|
|
|
|
|
EXPECT_EQ(original_refcnt + 1, strong_refcnt);
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// If we reset the first one, the refcount should be the original value.
|
2024-02-17 10:37:26 -09:00
|
|
|
owned.Reset();
|
|
|
|
|
strong_refcnt = Py_REFCNT(strong_ref.get());
|
|
|
|
|
EXPECT_EQ(original_refcnt, strong_refcnt);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestResetting) {
|
|
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
|
|
|
|
|
|
PyObject *new_dict = PyDict_New();
|
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
|
|
|
dict = Take<PythonDictionary>(new_dict);
|
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
|
|
|
EXPECT_EQ(new_dict, dict.get());
|
|
|
|
|
|
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
|
|
|
dict = Take<PythonDictionary>(PyDict_New());
|
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
|
|
|
EXPECT_NE(nullptr, dict.get());
|
|
|
|
|
dict.Reset();
|
|
|
|
|
EXPECT_EQ(nullptr, dict.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestBorrowedReferences) {
|
2024-02-17 10:37:26 -09:00
|
|
|
PythonByteArray byte_value(PyRefType::Owned,
|
|
|
|
|
PyByteArray_FromStringAndSize("foo", 3));
|
|
|
|
|
Py_ssize_t original_refcnt = Py_REFCNT(byte_value.get());
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_LE(1, original_refcnt);
|
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
|
|
|
|
2024-02-17 10:37:26 -09:00
|
|
|
PythonByteArray borrowed_byte(PyRefType::Borrowed, byte_value.get());
|
|
|
|
|
Py_ssize_t borrowed_refcnt = Py_REFCNT(borrowed_byte.get());
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(original_refcnt + 1, borrowed_refcnt);
|
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
|
|
|
}
|
|
|
|
|
|
2015-11-11 08:59:49 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject sys_module = m_main_module.ResolveName("sys");
|
|
|
|
|
EXPECT_EQ(m_sys_module.get(), sys_module.get());
|
2015-11-11 08:59:49 -09:00
|
|
|
EXPECT_TRUE(sys_module.IsAllocated());
|
|
|
|
|
EXPECT_TRUE(PythonModule::Check(sys_module.get()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject sys_path = m_sys_module.ResolveName("path");
|
|
|
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
2015-11-11 08:59:49 -09:00
|
|
|
EXPECT_TRUE(sys_path.IsAllocated());
|
|
|
|
|
EXPECT_TRUE(sys_version_info.IsAllocated());
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(PythonList::Check(sys_path.get()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
2015-11-11 08:59:49 -09:00
|
|
|
|
|
|
|
|
PythonObject version_info_type(PyRefType::Owned,
|
|
|
|
|
PyObject_Type(sys_version_info.get()));
|
|
|
|
|
EXPECT_TRUE(version_info_type.IsAllocated());
|
|
|
|
|
PythonObject major_version_field = version_info_type.ResolveName("major");
|
|
|
|
|
EXPECT_TRUE(major_version_field.IsAllocated());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
2015-11-11 08:59:49 -09:00
|
|
|
PythonObject major_version_field = sys_version_info.ResolveName("major");
|
|
|
|
|
PythonObject minor_version_field = sys_version_info.ResolveName("minor");
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(major_version_field.IsAllocated());
|
|
|
|
|
EXPECT_TRUE(minor_version_field.IsAllocated());
|
|
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto major_version_value = As<long long>(major_version_field);
|
|
|
|
|
auto minor_version_value = As<long long>(minor_version_field);
|
2015-11-11 08:59:49 -09:00
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
EXPECT_THAT_EXPECTED(major_version_value, llvm::HasValue(PY_MAJOR_VERSION));
|
|
|
|
|
EXPECT_THAT_EXPECTED(minor_version_value, llvm::HasValue(PY_MINOR_VERSION));
|
2015-11-11 08:59:49 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot) {
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject sys_path = m_main_module.ResolveName("sys.path");
|
2015-11-11 08:59:49 -09:00
|
|
|
EXPECT_TRUE(sys_path.IsAllocated());
|
|
|
|
|
EXPECT_TRUE(PythonList::Check(sys_path.get()));
|
|
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto version_major =
|
|
|
|
|
As<long long>(m_main_module.ResolveName("sys.version_info.major"));
|
|
|
|
|
|
|
|
|
|
auto version_minor =
|
|
|
|
|
As<long long>(m_main_module.ResolveName("sys.version_info.minor"));
|
|
|
|
|
|
|
|
|
|
EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
|
|
|
|
|
EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
|
2015-11-11 08:59:49 -09:00
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot) {
|
|
|
|
|
// Make up a custom dictionary with "sys" pointing to the `sys` module.
|
|
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
|
dict.SetItemForKey(PythonString("sys"), m_sys_module);
|
|
|
|
|
|
|
|
|
|
// Now use that dictionary to resolve `sys.version_info.major`
|
2020-05-08 09:56:30 -08:00
|
|
|
auto version_major = As<long long>(
|
|
|
|
|
PythonObject::ResolveNameWithDictionary("sys.version_info.major", dict));
|
|
|
|
|
|
|
|
|
|
auto version_minor = As<long long>(
|
|
|
|
|
PythonObject::ResolveNameWithDictionary("sys.version_info.minor", dict));
|
|
|
|
|
|
|
|
|
|
EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
|
|
|
|
|
EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
|
2015-11-11 10:42:27 -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
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonInteger) {
|
2018-11-02 14:34:51 -08:00
|
|
|
// Test that integers behave correctly when wrapped by a PythonInteger.
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Verify that `PythonInteger` works correctly when given a PyLong object.
|
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
|
|
|
PyObject *py_long = PyLong_FromLong(12);
|
|
|
|
|
EXPECT_TRUE(PythonInteger::Check(py_long));
|
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
|
|
|
PythonInteger python_long(PyRefType::Owned, py_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
|
|
|
EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
|
|
|
|
|
|
|
|
|
|
// Verify that you can reset the value and that it is reflected properly.
|
|
|
|
|
python_long.SetInteger(40);
|
2020-05-08 09:56:30 -08:00
|
|
|
auto e = As<long long>(python_long);
|
|
|
|
|
EXPECT_THAT_EXPECTED(e, llvm::HasValue(40));
|
2015-10-14 13:06:13 -08:00
|
|
|
|
|
|
|
|
// Test that creating a `PythonInteger` object works correctly with the
|
|
|
|
|
// int constructor.
|
|
|
|
|
PythonInteger constructed_int(7);
|
2020-05-08 09:56:30 -08:00
|
|
|
auto value = As<long long>(constructed_int);
|
|
|
|
|
EXPECT_THAT_EXPECTED(value, llvm::HasValue(7));
|
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
|
|
|
}
|
|
|
|
|
|
2019-02-16 09:39:14 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonBoolean) {
|
|
|
|
|
// Test PythonBoolean constructed from Py_True
|
|
|
|
|
EXPECT_TRUE(PythonBoolean::Check(Py_True));
|
|
|
|
|
PythonBoolean python_true(PyRefType::Owned, Py_True);
|
|
|
|
|
EXPECT_EQ(PyObjectType::Boolean, python_true.GetObjectType());
|
|
|
|
|
|
|
|
|
|
// Test PythonBoolean constructed from Py_False
|
|
|
|
|
EXPECT_TRUE(PythonBoolean::Check(Py_False));
|
|
|
|
|
PythonBoolean python_false(PyRefType::Owned, Py_False);
|
|
|
|
|
EXPECT_EQ(PyObjectType::Boolean, python_false.GetObjectType());
|
|
|
|
|
|
|
|
|
|
auto test_from_long = [](long value) {
|
|
|
|
|
PyObject *py_bool = PyBool_FromLong(value);
|
|
|
|
|
EXPECT_TRUE(PythonBoolean::Check(py_bool));
|
|
|
|
|
PythonBoolean python_boolean(PyRefType::Owned, py_bool);
|
|
|
|
|
EXPECT_EQ(PyObjectType::Boolean, python_boolean.GetObjectType());
|
|
|
|
|
EXPECT_EQ(bool(value), python_boolean.GetValue());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Test PythonBoolean constructed from long integer values.
|
2024-02-21 21:59:03 -09:00
|
|
|
test_from_long(0); // Test 'false' value.
|
|
|
|
|
test_from_long(1); // Test 'true' value.
|
2019-02-16 09:39:14 -09:00
|
|
|
test_from_long(~0); // Any value != 0 is 'true'.
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-11 13:16:12 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonBytes) {
|
|
|
|
|
static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
|
|
|
|
|
PyObject *py_bytes = PyBytes_FromString(test_bytes);
|
|
|
|
|
EXPECT_TRUE(PythonBytes::Check(py_bytes));
|
|
|
|
|
PythonBytes python_bytes(PyRefType::Owned, py_bytes);
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(PythonString::Check(py_bytes));
|
2016-02-25 08:41:59 -09:00
|
|
|
EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
|
2016-01-11 13:16:12 -09:00
|
|
|
|
|
|
|
|
llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
|
|
|
|
|
EXPECT_EQ(bytes.size(), strlen(test_bytes));
|
|
|
|
|
EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-25 14:21:09 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonByteArray) {
|
|
|
|
|
static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
|
|
|
|
|
llvm::StringRef orig_bytes(test_bytes);
|
|
|
|
|
PyObject *py_bytes =
|
|
|
|
|
PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
|
|
|
|
|
EXPECT_TRUE(PythonByteArray::Check(py_bytes));
|
|
|
|
|
PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
|
|
|
|
|
EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
|
|
|
|
|
EXPECT_EQ(after_bytes.size(), orig_bytes.size());
|
|
|
|
|
EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonString) {
|
|
|
|
|
// Test that strings behave correctly when wrapped by a PythonString.
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
|
|
|
|
|
static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
|
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
|
|
|
|
|
|
|
|
// Verify that `PythonString` works correctly when given a PyUnicode object.
|
|
|
|
|
PyObject *py_unicode = PyUnicode_FromString(test_string);
|
|
|
|
|
EXPECT_TRUE(PythonString::Check(py_unicode));
|
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
|
|
|
PythonString python_unicode(PyRefType::Owned, py_unicode);
|
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
|
|
|
EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
|
|
|
|
|
EXPECT_STREQ(test_string, python_unicode.GetString().data());
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Test that creating a `PythonString` object works correctly with the
|
|
|
|
|
// string constructor
|
2016-02-03 11:48:09 -09:00
|
|
|
PythonString constructed_string(test_string2);
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(test_string2, constructed_string.GetString());
|
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
|
|
|
}
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonStringToStr) {
|
2016-11-16 12:45:11 -09:00
|
|
|
const char *GetString = "PythonDataObjectsTest::TestPythonStringToStr";
|
2015-10-14 13:06:13 -08:00
|
|
|
|
2016-11-16 12:45:11 -09:00
|
|
|
PythonString str(GetString);
|
|
|
|
|
EXPECT_EQ(GetString, str.GetString());
|
2015-10-14 13:06:13 -08:00
|
|
|
|
|
|
|
|
PythonString str_str = str.Str();
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(GetString, str_str.GetString());
|
2015-10-14 13:06:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr) {}
|
|
|
|
|
|
2023-05-22 12:52:09 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredUnsignedInteger) {
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonInteger integer(7);
|
|
|
|
|
auto int_sp = integer.CreateStructuredInteger();
|
2023-05-22 12:52:09 -08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
|
std::holds_alternative<StructuredData::UnsignedIntegerSP>(int_sp));
|
|
|
|
|
StructuredData::UnsignedIntegerSP uint_sp =
|
|
|
|
|
std::get<StructuredData::UnsignedIntegerSP>(int_sp);
|
|
|
|
|
EXPECT_EQ(7U, uint_sp->GetValue());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredSignedInteger) {
|
|
|
|
|
PythonInteger integer(-42);
|
|
|
|
|
auto int_sp = integer.CreateStructuredInteger();
|
|
|
|
|
EXPECT_TRUE(std::holds_alternative<StructuredData::SignedIntegerSP>(int_sp));
|
|
|
|
|
StructuredData::SignedIntegerSP sint_sp =
|
|
|
|
|
std::get<StructuredData::SignedIntegerSP>(int_sp);
|
|
|
|
|
EXPECT_EQ(-42, sint_sp->GetValue());
|
2015-10-14 13:06:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString) {
|
|
|
|
|
static const char *test_string =
|
|
|
|
|
"PythonDataObjectsTest::TestPythonStringToStructuredString";
|
|
|
|
|
PythonString constructed_string(test_string);
|
|
|
|
|
auto string_sp = constructed_string.CreateStructuredString();
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(test_string, string_sp->GetStringValue());
|
2015-10-14 13:06:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListValueEquality) {
|
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
|
|
|
// Test that a list which is built through the native
|
|
|
|
|
// Python API behaves correctly when wrapped by a PythonList.
|
2016-02-03 11:48:09 -09:00
|
|
|
static const unsigned list_size = 2;
|
2015-10-14 13:06:13 -08:00
|
|
|
static const long long_value0 = 5;
|
|
|
|
|
static const char *const string_value1 = "String Index 1";
|
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
|
|
|
|
|
|
|
|
PyObject *py_list = PyList_New(2);
|
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
|
|
|
EXPECT_TRUE(PythonList::Check(py_list));
|
|
|
|
|
PythonList list(PyRefType::Owned, py_list);
|
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
|
|
|
|
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 list_items[list_size];
|
2019-10-17 14:22:09 -08:00
|
|
|
list_items[0] = PythonInteger(long_value0);
|
|
|
|
|
list_items[1] = PythonString(string_value1);
|
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
|
|
|
|
2016-02-03 11:48:09 -09:00
|
|
|
for (unsigned i = 0; i < list_size; ++i)
|
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
|
|
|
list.SetItemAtIndex(i, list_items[i]);
|
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
|
|
|
|
|
|
|
|
EXPECT_EQ(list_size, list.GetSize());
|
|
|
|
|
EXPECT_EQ(PyObjectType::List, list.GetObjectType());
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Verify that the values match
|
|
|
|
|
PythonObject chk_value1 = list.GetItemAtIndex(0);
|
|
|
|
|
PythonObject chk_value2 = list.GetItemAtIndex(1);
|
|
|
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
|
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
|
|
|
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
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
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto chkint = As<long long>(chk_value1);
|
|
|
|
|
ASSERT_THAT_EXPECTED(chkint, llvm::HasValue(long_value0));
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(string_value1, chk_str.GetString());
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListManipulation) {
|
|
|
|
|
// Test that manipulation of a PythonList behaves correctly when
|
|
|
|
|
// wrapped by a PythonDictionary.
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
static const long long_value0 = 5;
|
|
|
|
|
static const char *const string_value1 = "String Index 1";
|
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
|
|
|
|
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 list(PyInitialValue::Empty);
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonInteger integer(long_value0);
|
|
|
|
|
PythonString string(string_value1);
|
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
|
|
|
|
|
|
|
|
list.AppendItem(integer);
|
|
|
|
|
list.AppendItem(string);
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(2U, list.GetSize());
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Verify that the values match
|
|
|
|
|
PythonObject chk_value1 = list.GetItemAtIndex(0);
|
|
|
|
|
PythonObject chk_value2 = list.GetItemAtIndex(1);
|
|
|
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
|
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
|
|
|
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
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
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto e = As<long long>(chk_int);
|
|
|
|
|
EXPECT_THAT_EXPECTED(e, llvm::HasValue(long_value0));
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(string_value1, chk_str.GetString());
|
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
|
|
|
}
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList) {
|
|
|
|
|
static const long long_value0 = 5;
|
|
|
|
|
static const char *const string_value1 = "String Index 1";
|
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
|
|
|
|
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 list(PyInitialValue::Empty);
|
2015-10-14 13:06:13 -08:00
|
|
|
list.AppendItem(PythonInteger(long_value0));
|
|
|
|
|
list.AppendItem(PythonString(string_value1));
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
auto array_sp = list.CreateStructuredArray();
|
2017-05-29 00:25:46 -08:00
|
|
|
EXPECT_EQ(lldb::eStructuredDataTypeInteger,
|
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
|
|
|
array_sp->GetItemAtIndex(0)->GetType());
|
2017-05-29 00:25:46 -08:00
|
|
|
EXPECT_EQ(lldb::eStructuredDataTypeString,
|
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
|
|
|
array_sp->GetItemAtIndex(1)->GetType());
|
2015-10-14 13:06:13 -08:00
|
|
|
|
2023-05-22 12:52:09 -08:00
|
|
|
auto int_sp = array_sp->GetItemAtIndex(0)->GetAsUnsignedInteger();
|
2015-10-14 13:06:13 -08:00
|
|
|
auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
|
|
|
|
|
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(long_value0, long(int_sp->GetValue()));
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(string_value1, string_sp->GetValue());
|
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
|
|
|
}
|
|
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleSize) {
|
|
|
|
|
PythonTuple tuple(PyInitialValue::Empty);
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(0U, tuple.GetSize());
|
2015-11-11 10:42:27 -09:00
|
|
|
|
|
|
|
|
tuple = PythonTuple(3);
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
2015-11-11 10:42:27 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleValues) {
|
|
|
|
|
PythonTuple tuple(3);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonInteger int_value(1);
|
|
|
|
|
PythonString string_value("Test");
|
|
|
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
tuple.SetItemAtIndex(0, int_value);
|
|
|
|
|
tuple.SetItemAtIndex(1, string_value);
|
|
|
|
|
tuple.SetItemAtIndex(2, none_value);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
2015-11-11 10:42:27 -09:00
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList) {
|
|
|
|
|
PythonInteger int_value(1);
|
|
|
|
|
PythonString string_value("Test");
|
|
|
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
|
|
|
|
PythonTuple tuple{int_value, string_value, none_value};
|
|
|
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2) {
|
|
|
|
|
PythonInteger int_value(1);
|
|
|
|
|
PythonString string_value("Test");
|
|
|
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonTuple tuple{int_value.get(), string_value.get(), none_value.get()};
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
2015-11-11 10:42:27 -09:00
|
|
|
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList) {
|
|
|
|
|
PythonInteger int_value(1);
|
|
|
|
|
PythonString string_value("Test");
|
|
|
|
|
|
|
|
|
|
PythonTuple tuple{int_value.get(), string_value.get()};
|
|
|
|
|
|
|
|
|
|
auto array_sp = tuple.CreateStructuredArray();
|
|
|
|
|
EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
|
2017-05-29 00:25:46 -08:00
|
|
|
EXPECT_EQ(lldb::eStructuredDataTypeInteger,
|
2015-11-11 10:42:27 -09:00
|
|
|
array_sp->GetItemAtIndex(0)->GetType());
|
2017-05-29 00:25:46 -08:00
|
|
|
EXPECT_EQ(lldb::eStructuredDataTypeString,
|
2015-11-11 10:42:27 -09:00
|
|
|
array_sp->GetItemAtIndex(1)->GetType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
|
|
|
|
|
// Test that a dictionary which is built through the native
|
|
|
|
|
// Python API behaves correctly when wrapped by a PythonDictionary.
|
|
|
|
|
static const unsigned dict_entries = 2;
|
2015-10-14 13:06:13 -08:00
|
|
|
const char *key_0 = "Key 0";
|
|
|
|
|
int key_1 = 1;
|
|
|
|
|
const int value_0 = 0;
|
|
|
|
|
const char *value_1 = "Value 1";
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonObject py_keys[dict_entries];
|
|
|
|
|
PythonObject py_values[dict_entries];
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2019-10-17 14:22:09 -08:00
|
|
|
py_keys[0] = PythonString(key_0);
|
|
|
|
|
py_keys[1] = PythonInteger(key_1);
|
|
|
|
|
py_values[0] = PythonInteger(value_0);
|
|
|
|
|
py_values[1] = PythonString(value_1);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PyObject *py_dict = PyDict_New();
|
|
|
|
|
EXPECT_TRUE(PythonDictionary::Check(py_dict));
|
|
|
|
|
PythonDictionary dict(PyRefType::Owned, py_dict);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
for (unsigned i = 0; i < dict_entries; ++i)
|
2015-10-14 13:06:13 -08:00
|
|
|
PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
|
|
|
|
|
EXPECT_EQ(dict.GetSize(), dict_entries);
|
|
|
|
|
EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Verify that the values match
|
|
|
|
|
PythonObject chk_value1 = dict.GetItemForKey(py_keys[0]);
|
|
|
|
|
PythonObject chk_value2 = dict.GetItemForKey(py_keys[1]);
|
2015-11-11 10:42:27 -09:00
|
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
|
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
|
|
|
|
|
|
|
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
2020-05-08 09:56:30 -08:00
|
|
|
auto chkint = As<long long>(chk_value1);
|
2015-11-11 10:42:27 -09:00
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(value_1, chk_str.GetString());
|
2015-11-11 10:42:27 -09:00
|
|
|
}
|
|
|
|
|
|
[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
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryGetItemWithInvalidKey) {
|
|
|
|
|
// A PythonString constructed from invalid UTF-8 silently fails (the
|
|
|
|
|
// PyUnicode_FromStringAndSize call returns NULL) and leaves m_py_obj == NULL.
|
|
|
|
|
// PythonDictionary::GetItem(const PythonObject&) must not pass that NULL key
|
|
|
|
|
// through to PyDict_GetItemWithError, which would then dereference it and
|
|
|
|
|
// crash.
|
|
|
|
|
llvm::StringRef invalid_utf8("\xd0p", 2);
|
|
|
|
|
PythonString invalid_key(invalid_utf8);
|
|
|
|
|
EXPECT_FALSE(invalid_key.IsValid());
|
|
|
|
|
|
|
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
|
dict.SetItemForKey(PythonString("real_key"), PythonInteger(42));
|
|
|
|
|
|
|
|
|
|
// GetItem must return an error (not crash) when given an invalid key.
|
|
|
|
|
llvm::Expected<PythonObject> item = dict.GetItem(invalid_key);
|
|
|
|
|
EXPECT_FALSE(static_cast<bool>(item));
|
|
|
|
|
llvm::consumeError(item.takeError());
|
|
|
|
|
|
|
|
|
|
// GetItemForKey wraps GetItem, consumes any error, and returns an empty
|
|
|
|
|
// PythonObject. It must not crash either.
|
|
|
|
|
PythonObject result = dict.GetItemForKey(invalid_key);
|
|
|
|
|
EXPECT_FALSE(result.IsAllocated());
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
|
|
|
|
|
// Test that manipulation of a dictionary behaves correctly when wrapped
|
|
|
|
|
// by a PythonDictionary.
|
2016-02-03 11:48:09 -09:00
|
|
|
static const unsigned dict_entries = 2;
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
const char *const key_0 = "Key 0";
|
|
|
|
|
const char *const key_1 = "Key 1";
|
|
|
|
|
const long value_0 = 1;
|
|
|
|
|
const char *const value_1 = "Value 1";
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonString keys[dict_entries];
|
|
|
|
|
PythonObject values[dict_entries];
|
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
|
|
|
|
2019-10-17 14:22:09 -08:00
|
|
|
keys[0] = PythonString(key_0);
|
|
|
|
|
keys[1] = PythonString(key_1);
|
|
|
|
|
values[0] = PythonInteger(value_0);
|
|
|
|
|
values[1] = PythonString(value_1);
|
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
|
|
|
|
2016-02-03 11:48:09 -09:00
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
|
for (int i = 0; i < 2; ++i)
|
2015-10-14 13:06:13 -08:00
|
|
|
dict.SetItemForKey(keys[i], values[i]);
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_EQ(dict_entries, dict.GetSize());
|
2023-11-07 21:01:21 -09:00
|
|
|
EXPECT_FALSE(dict.HasKey("not_in_dict"));
|
|
|
|
|
EXPECT_TRUE(dict.HasKey(key_0));
|
|
|
|
|
EXPECT_TRUE(dict.HasKey(key_1));
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
// Verify that the keys and values match
|
|
|
|
|
PythonObject chk_value1 = dict.GetItemForKey(keys[0]);
|
|
|
|
|
PythonObject chk_value2 = dict.GetItemForKey(keys[1]);
|
|
|
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
|
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
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
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto chkint = As<long long>(chk_value1);
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(value_1, chk_str.GetString());
|
2015-10-14 13:06:13 -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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary) {
|
|
|
|
|
static const char *const string_key0 = "String Key 0";
|
2016-02-03 11:48:09 -09:00
|
|
|
static const char *const string_key1 = "String Key 1";
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
static const char *const string_value0 = "String Value 0";
|
|
|
|
|
static const long int_value1 = 7;
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
|
dict.SetItemForKey(PythonString(string_key0), PythonString(string_value0));
|
|
|
|
|
dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
auto dict_sp = dict.CreateStructuredDictionary();
|
|
|
|
|
EXPECT_EQ(2U, dict_sp->GetSize());
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_TRUE(dict_sp->HasKey(string_key0));
|
|
|
|
|
EXPECT_TRUE(dict_sp->HasKey(string_key1));
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
auto string_sp = dict_sp->GetValueForKey(string_key0)->GetAsString();
|
2023-05-22 12:52:09 -08:00
|
|
|
auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsUnsignedInteger();
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2016-11-16 12:45:11 -09:00
|
|
|
EXPECT_EQ(string_value0, string_sp->GetValue());
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_EQ(int_value1, long(int_sp->GetValue()));
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonCallableCheck) {
|
|
|
|
|
PythonObject sys_exc_info = m_sys_module.ResolveName("exc_info");
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonObject none(PyRefType::Borrowed, Py_None);
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-11-11 10:42:27 -09:00
|
|
|
EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_FALSE(PythonCallable::Check(none.get()));
|
2016-09-06 12:57:50 -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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
|
|
|
|
|
auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>();
|
|
|
|
|
PythonInteger one(1);
|
2015-11-11 10:42:27 -09:00
|
|
|
PythonString two("two");
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonTuple three = {one, two};
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
PythonTuple tuple_to_convert = {one, two, three};
|
|
|
|
|
PythonObject result = list({tuple_to_convert});
|
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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_TRUE(PythonList::Check(result.get()));
|
2015-11-11 10:42:27 -09:00
|
|
|
auto list_result = result.AsType<PythonList>();
|
2016-02-03 11:48:09 -09:00
|
|
|
EXPECT_EQ(3U, list_result.GetSize());
|
2015-11-11 10:42:27 -09:00
|
|
|
EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
|
2015-10-14 13:06:13 -08:00
|
|
|
EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
|
2015-11-11 10:42:27 -09:00
|
|
|
EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
|
2016-09-06 12:57:50 -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
|
|
|
|
2015-10-14 13:06:13 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonFile) {
|
2019-09-26 09:54:59 -08:00
|
|
|
auto file = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
|
2021-07-28 10:07:03 -08:00
|
|
|
File::eOpenOptionReadOnly);
|
2019-09-26 09:54:59 -08:00
|
|
|
ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
|
2019-10-16 17:35:22 -08:00
|
|
|
auto py_file = PythonFile::FromFile(*file.get(), "r");
|
|
|
|
|
ASSERT_THAT_EXPECTED(py_file, llvm::Succeeded());
|
|
|
|
|
EXPECT_TRUE(PythonFile::Check(py_file.get().get()));
|
2015-10-15 11:35:48 -08:00
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2015-10-16 09:51:49 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestObjectAttributes) {
|
|
|
|
|
PythonInteger py_int(42);
|
|
|
|
|
EXPECT_TRUE(py_int.HasAttribute("numerator"));
|
|
|
|
|
EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2020-05-08 09:56:30 -08:00
|
|
|
auto numerator_attr = As<long long>(py_int.GetAttributeValue("numerator"));
|
|
|
|
|
|
|
|
|
|
EXPECT_THAT_EXPECTED(numerator_attr, llvm::HasValue(42));
|
2016-02-03 11:48:09 -09:00
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
|
2016-08-10 15:25:57 -08:00
|
|
|
TEST_F(PythonDataObjectsTest, TestExtractingUInt64ThroughStructuredData) {
|
|
|
|
|
// Make up a custom dictionary with "sys" pointing to the `sys` module.
|
|
|
|
|
const char *key_name = "addr";
|
|
|
|
|
const uint64_t value = 0xf000000000000000ull;
|
|
|
|
|
PythonDictionary python_dict(PyInitialValue::Empty);
|
|
|
|
|
PythonInteger python_ull_value(PyRefType::Owned,
|
|
|
|
|
PyLong_FromUnsignedLongLong(value));
|
|
|
|
|
python_dict.SetItemForKey(PythonString(key_name), python_ull_value);
|
|
|
|
|
StructuredData::ObjectSP structured_data_sp =
|
|
|
|
|
python_dict.CreateStructuredObject();
|
|
|
|
|
EXPECT_TRUE((bool)structured_data_sp);
|
|
|
|
|
if (structured_data_sp) {
|
|
|
|
|
StructuredData::Dictionary *structured_dict_ptr =
|
|
|
|
|
structured_data_sp->GetAsDictionary();
|
|
|
|
|
EXPECT_TRUE(structured_dict_ptr != nullptr);
|
|
|
|
|
if (structured_dict_ptr) {
|
|
|
|
|
StructuredData::ObjectSP structured_addr_value_sp =
|
|
|
|
|
structured_dict_ptr->GetValueForKey(key_name);
|
|
|
|
|
EXPECT_TRUE((bool)structured_addr_value_sp);
|
|
|
|
|
const uint64_t extracted_value =
|
2023-05-22 12:52:09 -08:00
|
|
|
structured_addr_value_sp->GetUnsignedIntegerValue(123);
|
2016-08-10 15:25:57 -08:00
|
|
|
EXPECT_TRUE(extracted_value == value);
|
|
|
|
|
}
|
2016-09-06 12:57:50 -08:00
|
|
|
}
|
2016-08-10 15:25:57 -08:00
|
|
|
}
|
2019-10-17 14:22:06 -08:00
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestCallable) {
|
|
|
|
|
|
|
|
|
|
PythonDictionary globals(PyInitialValue::Empty);
|
|
|
|
|
auto builtins = PythonModule::BuiltinsModule();
|
|
|
|
|
llvm::Error error = globals.SetItem("__builtins__", builtins);
|
|
|
|
|
ASSERT_FALSE(error);
|
|
|
|
|
|
|
|
|
|
{
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o =
|
|
|
|
|
RunString("lambda x : x", Py_eval_input, globals.get(), globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
auto lambda = Take<PythonCallable>(o);
|
|
|
|
|
auto arginfo = lambda.GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o = RunString("lambda x,y=0: x", Py_eval_input, globals.get(),
|
|
|
|
|
globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
auto lambda = Take<PythonCallable>(o);
|
|
|
|
|
auto arginfo = lambda.GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o = RunString("lambda x,y=0, **kw: x", Py_eval_input,
|
|
|
|
|
globals.get(), globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
auto lambda = Take<PythonCallable>(o);
|
|
|
|
|
auto arginfo = lambda.GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o = RunString("lambda x,y,*a: x", Py_eval_input, globals.get(),
|
|
|
|
|
globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
auto lambda = Take<PythonCallable>(o);
|
|
|
|
|
auto arginfo = lambda.GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args,
|
|
|
|
|
PythonCallable::ArgInfo::UNBOUNDED);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-08-01 14:27:14 -08:00
|
|
|
PyObject *o = RunString("lambda x,y,*a,**kw: x", Py_eval_input,
|
|
|
|
|
globals.get(), globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
auto lambda = Take<PythonCallable>(o);
|
|
|
|
|
auto arginfo = lambda.GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args,
|
|
|
|
|
PythonCallable::ArgInfo::UNBOUNDED);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const char *script = R"(
|
|
|
|
|
class Foo:
|
|
|
|
|
def bar(self, x):
|
|
|
|
|
return x
|
2019-10-18 23:05:33 -08:00
|
|
|
@classmethod
|
|
|
|
|
def classbar(cls, x):
|
|
|
|
|
return x
|
|
|
|
|
@staticmethod
|
|
|
|
|
def staticbar(x):
|
|
|
|
|
return x
|
|
|
|
|
def __call__(self, x):
|
|
|
|
|
return x
|
|
|
|
|
obj = Foo()
|
2019-10-17 14:22:06 -08:00
|
|
|
bar_bound = Foo().bar
|
2019-10-18 23:05:33 -08:00
|
|
|
bar_class = Foo().classbar
|
|
|
|
|
bar_static = Foo().staticbar
|
2019-10-17 14:22:06 -08:00
|
|
|
bar_unbound = Foo.bar
|
2019-11-04 11:48:49 -09:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class OldStyle:
|
|
|
|
|
def __init__(self, one, two, three):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class NewStyle(object):
|
|
|
|
|
def __init__(self, one, two, three):
|
|
|
|
|
pass
|
|
|
|
|
|
[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
|
|
|
class NoConstructorAtAll:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
class NewOnlyVarArgs:
|
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
|
return super().__new__(cls)
|
|
|
|
|
|
|
|
|
|
class NewOnlyFixedArgs:
|
|
|
|
|
def __new__(cls, a, b):
|
|
|
|
|
return super().__new__(cls)
|
|
|
|
|
|
2019-10-17 14:22:06 -08:00
|
|
|
)";
|
|
|
|
|
PyObject *o =
|
2025-08-01 14:27:14 -08:00
|
|
|
RunString(script, Py_file_input, globals.get(), globals.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_FALSE(o == NULL);
|
|
|
|
|
Take<PythonObject>(o);
|
|
|
|
|
|
|
|
|
|
auto bar_bound = As<PythonCallable>(globals.GetItem("bar_bound"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(bar_bound, llvm::Succeeded());
|
|
|
|
|
auto arginfo = bar_bound.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
2019-10-17 14:22:06 -08:00
|
|
|
|
|
|
|
|
auto bar_unbound = As<PythonCallable>(globals.GetItem("bar_unbound"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(bar_unbound, llvm::Succeeded());
|
|
|
|
|
arginfo = bar_unbound.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
|
|
|
|
|
|
|
|
|
auto bar_class = As<PythonCallable>(globals.GetItem("bar_class"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(bar_class, llvm::Succeeded());
|
|
|
|
|
arginfo = bar_class.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
|
|
|
|
|
|
auto bar_static = As<PythonCallable>(globals.GetItem("bar_static"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(bar_static, llvm::Succeeded());
|
|
|
|
|
arginfo = bar_static.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
|
|
|
|
|
|
auto obj = As<PythonCallable>(globals.GetItem("obj"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(obj, llvm::Succeeded());
|
|
|
|
|
arginfo = obj.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
2019-11-04 11:48:49 -09:00
|
|
|
|
|
|
|
|
auto oldstyle = As<PythonCallable>(globals.GetItem("OldStyle"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(oldstyle, llvm::Succeeded());
|
|
|
|
|
arginfo = oldstyle.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 3u);
|
|
|
|
|
|
|
|
|
|
auto newstyle = As<PythonCallable>(globals.GetItem("NewStyle"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(newstyle, llvm::Succeeded());
|
|
|
|
|
arginfo = newstyle.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 3u);
|
[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
|
|
|
|
|
|
|
|
// Neither __init__ nor __new__ overridden: object.__init__ truly takes
|
|
|
|
|
// no extra arguments here.
|
|
|
|
|
auto no_ctor = As<PythonCallable>(globals.GetItem("NoConstructorAtAll"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(no_ctor, llvm::Succeeded());
|
|
|
|
|
arginfo = no_ctor.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 0u);
|
|
|
|
|
|
|
|
|
|
// __init__ not overridden, but __new__ is: object.__init__ becomes
|
|
|
|
|
// lenient about extra arguments once __new__ is overridden, so the
|
|
|
|
|
// argument count has to come from __new__, not from __init__ alone.
|
|
|
|
|
auto new_varargs = As<PythonCallable>(globals.GetItem("NewOnlyVarArgs"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(new_varargs, llvm::Succeeded());
|
|
|
|
|
arginfo = new_varargs.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args,
|
|
|
|
|
PythonCallable::ArgInfo::UNBOUNDED);
|
|
|
|
|
|
|
|
|
|
auto new_fixed = As<PythonCallable>(globals.GetItem("NewOnlyFixedArgs"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(new_fixed, llvm::Succeeded());
|
|
|
|
|
arginfo = new_fixed.get().GetArgInfo();
|
|
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto builtins = PythonModule::BuiltinsModule();
|
|
|
|
|
auto hex = As<PythonCallable>(builtins.GetAttribute("hex"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(hex, llvm::Succeeded());
|
[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
|
|
|
auto arginfo = PythonCallable::GetArgInfoFromInspectSignature(hex.get());
|
2019-10-17 14:22:06 -08:00
|
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
2019-10-18 23:05:33 -08:00
|
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
2019-10-17 14:22:06 -08:00
|
|
|
}
|
2019-10-21 18:32:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestScript) {
|
|
|
|
|
|
|
|
|
|
static const char script[] = R"(
|
|
|
|
|
def factorial(n):
|
|
|
|
|
if n > 1:
|
|
|
|
|
return n * factorial(n-1)
|
|
|
|
|
else:
|
|
|
|
|
return 1;
|
|
|
|
|
main = factorial
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
PythonScript factorial(script);
|
|
|
|
|
|
|
|
|
|
EXPECT_THAT_EXPECTED(As<long long>(factorial(5ll)), llvm::HasValue(120));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestExceptions) {
|
|
|
|
|
|
|
|
|
|
static const char script[] = R"(
|
|
|
|
|
def foo():
|
|
|
|
|
return bar()
|
|
|
|
|
def bar():
|
|
|
|
|
return baz()
|
|
|
|
|
def baz():
|
|
|
|
|
return 1 / 0
|
|
|
|
|
main = foo
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
PythonScript foo(script);
|
|
|
|
|
|
2019-10-21 20:00:37 -08:00
|
|
|
EXPECT_THAT_EXPECTED(
|
|
|
|
|
foo(), llvm::Failed<PythonException>(testing::Property(
|
|
|
|
|
&PythonException::ReadBacktrace,
|
|
|
|
|
testing::AllOf(testing::ContainsRegex("line 3, in foo"),
|
|
|
|
|
testing::ContainsRegex("line 5, in bar"),
|
|
|
|
|
testing::ContainsRegex("line 7, in baz"),
|
|
|
|
|
testing::ContainsRegex("ZeroDivisionError")))));
|
2019-10-21 18:32:37 -08:00
|
|
|
|
2024-02-21 21:59:03 -09:00
|
|
|
#if !((defined(_WIN32) || defined(_WIN64)) && \
|
|
|
|
|
(defined(__aarch64__) || defined(_M_ARM64)))
|
2023-01-03 05:40:57 -09:00
|
|
|
|
2019-10-21 18:32:37 -08:00
|
|
|
static const char script2[] = R"(
|
|
|
|
|
class MyError(Exception):
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.my_message
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
raise MyError("lol")
|
|
|
|
|
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
PythonScript lol(script2);
|
|
|
|
|
|
2023-03-15 14:44:17 -08:00
|
|
|
EXPECT_THAT_EXPECTED(
|
|
|
|
|
lol(),
|
|
|
|
|
llvm::Failed<PythonException>(testing::Property(
|
|
|
|
|
&PythonException::ReadBacktrace,
|
|
|
|
|
testing::AnyOf(
|
|
|
|
|
testing::ContainsRegex("MyError: <exception str\\(\\) failed>"),
|
|
|
|
|
testing::ContainsRegex("unprintable MyError")))));
|
2023-01-03 05:40:57 -09:00
|
|
|
|
|
|
|
|
#endif
|
2019-10-21 18:32:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonDataObjectsTest, TestRun) {
|
|
|
|
|
|
|
|
|
|
PythonDictionary globals(PyInitialValue::Empty);
|
|
|
|
|
|
|
|
|
|
auto x = As<long long>(runStringOneLine("40 + 2", globals, globals));
|
|
|
|
|
ASSERT_THAT_EXPECTED(x, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(x.get(), 42l);
|
|
|
|
|
|
|
|
|
|
Expected<PythonObject> r = runStringOneLine("n = 42", globals, globals);
|
|
|
|
|
ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
|
|
|
|
|
auto y = As<long long>(globals.GetItem("n"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(y, llvm::Succeeded());
|
|
|
|
|
EXPECT_EQ(y.get(), 42l);
|
|
|
|
|
|
|
|
|
|
const char script[] = R"(
|
|
|
|
|
def foobar():
|
|
|
|
|
return "foo" + "bar" + "baz"
|
|
|
|
|
g = foobar()
|
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
r = runStringMultiLine(script, globals, globals);
|
|
|
|
|
ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
|
|
|
|
|
auto g = As<std::string>(globals.GetItem("g"));
|
|
|
|
|
ASSERT_THAT_EXPECTED(g, llvm::HasValue("foobarbaz"));
|
2021-07-28 10:07:03 -08:00
|
|
|
}
|