Skip to content

Commit a0186fa

Browse files
committed
[lldb] Drop support for the Buffer Protocol
This is an alternative solution to the issue described in #167990, which can be summarized as that we cannot target Python 3.8 with the stable API and support building for Python 3.13 and later due to the buffer protocol. The approach taken in this PR, and proposed by Ismail, is to sidesteps the issue by dropping support for the buffer protocol. The only two users are SBFile::Read and SBFile::Write. Instead, we support PyBytes and PyByteArray which are the builtin types that conform to the buffer protocol. Technically, this means a small regression, where those methods could previously take custom types that conform to Python's buffer protocol. Like Ismail, I think this is acceptable given the alternatives.
1 parent 2743543 commit a0186fa

File tree

3 files changed

+34
-53
lines changed

3 files changed

+34
-53
lines changed

lldb/bindings/python/python-typemaps.swig

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -628,61 +628,34 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
628628
}
629629
}
630630

631-
// These two pybuffer macros are copied out of swig/Lib/python/pybuffer.i,
632-
// and fixed so they will not crash if PyObject_GetBuffer fails.
633-
// https://github.com/swig/swig/issues/1640
634-
//
635-
// I've also moved the call to PyBuffer_Release to the end of the SWIG wrapper,
636-
// doing it right away is not legal according to the python buffer protocol.
637-
%inline %{
638-
struct Py_buffer_RAII {
639-
Py_buffer buffer = {};
640-
Py_buffer_RAII(){};
641-
Py_buffer &operator=(const Py_buffer_RAII &) = delete;
642-
Py_buffer_RAII(const Py_buffer_RAII &) = delete;
643-
~Py_buffer_RAII() {
644-
if (buffer.obj)
645-
PyBuffer_Release(&buffer);
646-
}
647-
};
648-
%}
649631

650-
%define %pybuffer_mutable_binary(TYPEMAP, SIZE)
651-
%typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) {
652-
int res;
653-
Py_ssize_t size = 0;
654-
void *buf = 0;
655-
res = PyObject_GetBuffer($input, &view.buffer, PyBUF_WRITABLE);
656-
if (res < 0) {
657-
PyErr_Clear();
658-
%argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum);
659-
}
660-
size = view.buffer.len;
661-
buf = view.buffer.buf;
662-
$1 = ($1_ltype)buf;
663-
$2 = ($2_ltype)(size / sizeof($*1_type));
664-
}
665-
%enddef
666-
667-
%define %pybuffer_binary(TYPEMAP, SIZE)
668-
%typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) {
669-
int res;
670-
Py_ssize_t size = 0;
671-
const void *buf = 0;
672-
res = PyObject_GetBuffer($input, &view.buffer, PyBUF_CONTIG_RO);
673-
if (res < 0) {
674-
PyErr_Clear();
675-
%argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum);
632+
// Typemap for SBFile::Write.
633+
%typemap(in) (const uint8_t *buf, size_t num_bytes) {
634+
if (PythonByteArray::Check($input)) {
635+
PythonByteArray bytearray(PyRefType::Borrowed, $input);
636+
$1 = (uint8_t *)bytearray.GetBytes().data();
637+
$2 = bytearray.GetSize();
638+
} else if (PythonBytes::Check($input)) {
639+
PythonBytes bytes(PyRefType::Borrowed, $input);
640+
$1 = (uint8_t *)bytes.GetBytes().data();
641+
$2 = bytes.GetSize();
642+
} else {
643+
PyErr_SetString(PyExc_ValueError, "Expecting a bytes or bytearray object");
644+
SWIG_fail;
676645
}
677-
size = view.buffer.len;
678-
buf = view.buffer.buf;
679-
$1 = ($1_ltype)buf;
680-
$2 = ($2_ltype)(size / sizeof($*1_type));
681646
}
682-
%enddef
683647

684-
%pybuffer_binary(const uint8_t *buf, size_t num_bytes);
685-
%pybuffer_mutable_binary(uint8_t *buf, size_t num_bytes);
648+
// Typemap for SBFile::Read.
649+
%typemap(in) (uint8_t *buf, size_t num_bytes) {
650+
if (PythonByteArray::Check($input)) {
651+
PythonByteArray bytearray(PyRefType::Borrowed, $input);
652+
$1 = (uint8_t *)bytearray.GetBytes().data();
653+
$2 = bytearray.GetSize();
654+
} else {
655+
PyErr_SetString(PyExc_ValueError, "Expecting a bytearray");
656+
SWIG_fail;
657+
}
658+
}
686659

687660
%typemap(in) (const char **symbol_name, uint32_t num_names) {
688661
using namespace lldb_private;

lldb/bindings/python/python-wrapper.swig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,11 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallTypeScript(
128128

129129
PyObject *pfunc_impl = nullptr;
130130

131-
if (pyfunct_wrapper && *pyfunct_wrapper &&
132-
PyFunction_Check(*pyfunct_wrapper)) {
131+
if (pyfunct_wrapper && *pyfunct_wrapper
132+
#ifndef Py_LIMITED_API
133+
&& PyFunction_Check(*pyfunct_wrapper)
134+
#endif
135+
) {
133136
pfunc_impl = (PyObject *)(*pyfunct_wrapper);
134137
if (pfunc_impl->ob_refcnt == 1) {
135138
Py_XDECREF(pfunc_impl);

lldb/bindings/python/python.swig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ except ImportError:
5959
// Parameter types will be used in the autodoc string.
6060
%feature("autodoc", "1");
6161

62+
// Include lldb-python first as it sets Py_LIMITED_API.
63+
%begin %{
64+
#include "../source/Plugins/ScriptInterpreter/Python/lldb-python.h"
65+
%}
66+
6267
%pythoncode%{
6368
import uuid
6469
import re

0 commit comments

Comments
 (0)