Skip to content

Commit 800c126

Browse files
committed
[lldb] Require at least Python 3.11 when targeting the Limited C API
This is a continuation of my effort [1] to eliminate uses of the private Python API in LLDB. I found 3 more issues that were hidden in the typemap, because those were included before we defined Py_LIMITED_API. The primary motivator for bumping the minimum required Python version is our use of `pybuffer` (i.e. the Buffer Protocol). - For Python versions prior to Python 3.11, your only option was to target the "Old Buffer Protocol" [2], which has been deprecated since Python 3 and removed in Python 3.13, though the symbols still exist for ABI compatibility. - For Python versions 3.13 and later, because of the removal, your only option is to target the "New Buffer Protocol" [3] which was only added to the stable API in Python 3.11. This leads to certain combination of Python versions for building against and targeting with the limited API that are not compatible. For example, you cannot target the 3.8 stable API when building against Python 3.13 because the new version of Python doesn't declare the old APIs and you cannot use the new APIs yet. To make this more complicated, the use of the buffer protocol is coming from SWIG. Furthermore, all released versions of SWIG get this wrong. For unrelated reasons, to work around a bug in SWIG < 4.1, we already reimplement the swig type wrapper for the Buffer Protocol in a way that's compatible with Python 3.11 and later. Instead of waiting for a SWIG release that fixes this issue (it's already fixed on the master branch) we can keep the workaround and bump the minimum Python version when targeting the limited C API. [1] #151617 [2] https://docs.python.org/3.12/c-api/objbuffer.html [3] https://docs.python.org/3/c-api/buffer.html
1 parent 36848a3 commit 800c126

File tree

5 files changed

+27
-17
lines changed

5 files changed

+27
-17
lines changed

lldb/bindings/python/python-typemaps.swig

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,19 +220,19 @@ AND call SWIG_fail at the same time, because it will result in a double free.
220220
}
221221

222222
// Disable default type checking for this method to avoid SWIG dispatch issues.
223-
//
223+
//
224224
// Problem: SBThread::GetStopDescription has two overloads:
225-
// 1. GetStopDescription(char* dst_or_null, size_t dst_len)
225+
// 1. GetStopDescription(char* dst_or_null, size_t dst_len)
226226
// 2. GetStopDescription(lldb::SBStream& stream)
227227
//
228228
// SWIG generates a dispatch function to select the correct overload based on argument types.
229229
// see https://www.swig.org/Doc4.0/SWIGDocumentation.html#Typemaps_overloading.
230230
// However, this dispatcher doesn't consider typemaps that transform function signatures.
231231
//
232232
// In Python, our typemap converts GetStopDescription(char*, size_t) to GetStopDescription(int).
233-
// The dispatcher still checks against the original (char*, size_t) signature instead of
233+
// The dispatcher still checks against the original (char*, size_t) signature instead of
234234
// the transformed (int) signature, causing type matching to fail.
235-
// This only affects SBThread::GetStopDescription since the type check also matches
235+
// This only affects SBThread::GetStopDescription since the type check also matches
236236
// the argument name, which is unique to this function.
237237
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) (char *dst_or_null, size_t dst_len) ""
238238

@@ -628,12 +628,11 @@ 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.
631+
// These two pybuffer macros are copied out of swig/Lib/python/pybuffer.i.
632+
// - Avoids crash if PyObject_GetBuffer fails and delays calling
633+
// PyBuffer_Release (https://github.com/swig/swig/issues/1640)
634+
// - Avoids using deprecated "old buffer protocol" APIs when targeting the
635+
// Stable C API.
637636
%inline %{
638637
struct Py_buffer_RAII {
639638
Py_buffer buffer = {};

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

lldb/cmake/modules/LLDBConfig.cmake

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,14 @@ if (LLDB_ENABLE_PYTHON)
180180
"Path to use as PYTHONHOME in lldb. If a relative path is specified, it will be resolved at runtime relative to liblldb directory.")
181181
endif()
182182

183-
if (SWIG_VERSION VERSION_GREATER_EQUAL "4.2" AND NOT LLDB_EMBED_PYTHON_HOME)
183+
if (SWIG_VERSION VERSION_GREATER_EQUAL "4.2"
184+
Python3_VERSION VERSION_GREATER_EQUAL "3.11"
185+
AND NOT LLDB_EMBED_PYTHON_HOME)
184186
set(default_enable_python_limited_api ON)
185187
else()
186188
set(default_enable_python_limited_api OFF)
187189
endif()
188-
option(LLDB_ENABLE_PYTHON_LIMITED_API "Force LLDB to only use the Python Limited API (requires SWIG 4.2 or later)"
190+
option(LLDB_ENABLE_PYTHON_LIMITED_API "Only use the Python Limited API (requires at least Python 3.11 and SWIG 4.2)"
189191
${default_enable_python_limited_api})
190192
else()
191193
# Even if Python scripting is disabled, we still need a Python interpreter to

lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ static llvm::Expected<bool> *g_fcxx_modules_workaround [[maybe_unused]];
4545
#include <locale>
4646
#endif
4747

48-
#define LLDB_MINIMUM_PYTHON_VERSION 0x03080000
49-
50-
#if LLDB_ENABLE_PYTHON_LIMITED_API
5148
// If defined, LLDB will be ABI-compatible with all Python 3 releases from the
5249
// specified one onward, and can use Limited API introduced up to that version.
50+
#if LLDB_ENABLE_PYTHON_LIMITED_API
51+
#define LLDB_MINIMUM_PYTHON_VERSION 0x030b0000
5352
#define Py_LIMITED_API LLDB_MINIMUM_PYTHON_VERSION
53+
#else
54+
#define LLDB_MINIMUM_PYTHON_VERSION 0x03080000
5455
#endif
5556

5657
// Include python for non windows machines

0 commit comments

Comments
 (0)