Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0c74fc8

Browse files
encukouzooba
andauthored
gh-137210: Add a struct, slot & function for checking an extension's ABI (GH-137212)
Co-authored-by: Steve Dower <steve.dower@microsoft.com>
1 parent c1a9c23 commit 0c74fc8

24 files changed

+654
-8
lines changed

‎Doc/c-api/module.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,28 @@ The available slot types are:
388388
389389
.. versionadded:: 3.13
390390
391+
.. c:macro:: Py_mod_abi
392+
393+
A pointer to a :c:struct:`PyABIInfo` structure that describes the ABI that
394+
the extension is using.
395+
396+
When the module is loaded, the :c:struct:`!PyABIInfo` in this slot is checked
397+
using :c:func:`PyABIInfo_Check`.
398+
399+
A suitable :c:struct:`!PyABIInfo` variable can be defined using the
400+
:c:macro:`PyABIInfo_VAR` macro, as in:
401+
402+
.. code-block:: c
403+
404+
PyABIInfo_VAR(abi_info);
405+
406+
static PyModuleDef_Slot mymodule_slots[] = {
407+
{Py_mod_abi, &abi_info},
408+
...
409+
};
410+
411+
.. versionadded:: 3.15
412+
391413
392414
.. _moduledef-dynamic:
393415

‎Doc/c-api/stable.rst

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
.. _stable:
44

5-
***************
6-
C API Stability
7-
***************
5+
***********************
6+
C API and ABI Stability
7+
***********************
88

99
Unless documented otherwise, Python's C API is covered by the Backwards
1010
Compatibility Policy, :pep:`387`.
@@ -199,6 +199,162 @@ This is the case with Windows and macOS releases from ``python.org`` and many
199199
third-party distributors.
200200

201201

202+
ABI Checking
203+
============
204+
205+
.. versionadded:: next
206+
207+
Python includes a rudimentary check for ABI compatibility.
208+
209+
This check is not comprehensive.
210+
It only guards against common cases of incompatible modules being
211+
installed for the wrong interpreter.
212+
It also does not take :ref:`platform incompatibilities <stable-abi-platform>`
213+
into account.
214+
It can only be done after an extension is successfully loaded.
215+
216+
Despite these limitations, it is recommended that extension modules use this
217+
mechanism, so that detectable incompatibilities raise exceptions rather than
218+
crash.
219+
220+
Most modules can use this check via the :c:data:`Py_mod_abi`
221+
slot and the :c:macro:`PyABIInfo_VAR` macro, for example like this:
222+
223+
.. code-block:: c
224+
225+
PyABIInfo_VAR(abi_info);
226+
227+
static PyModuleDef_Slot mymodule_slots[] = {
228+
{Py_mod_abi, &abi_info},
229+
...
230+
};
231+
232+
233+
The full API is described below for advanced use cases.
234+
235+
.. c:function:: int PyABIInfo_Check(PyABIInfo *info, const char *module_name)
236+
237+
Verify that the given *info* is compatible with the currently running
238+
interpreter.
239+
240+
Return 0 on success. On failure, raise an exception and return -1.
241+
242+
If the ABI is incompatible, the raised exception will be :py:exc:`ImportError`.
243+
244+
The *module_name* argument can be ``NULL``, or point to a NUL-terminated
245+
UTF-8-encoded string used for error messages.
246+
247+
Note that if *info* describes the ABI that the current code uses (as defined
248+
by :c:macro:`PyABIInfo_VAR`, for example), using any other Python C API
249+
may lead to crashes.
250+
In particular, it is not safe to examine the raised exception.
251+
252+
.. versionadded:: next
253+
254+
.. c:macro:: PyABIInfo_VAR(NAME)
255+
256+
Define a static :c:struct:`PyABIInfo` variable with the given *NAME* that
257+
describes the ABI that the current code will use.
258+
This macro expands to:
259+
260+
.. code-block:: c
261+
262+
static PyABIInfo NAME = {
263+
1, 0,
264+
PyABIInfo_DEFAULT_FLAGS,
265+
PY_VERSION_HEX,
266+
PyABIInfo_DEFAULT_ABI_VERSION
267+
}
268+
269+
.. versionadded:: next
270+
271+
.. c:type:: PyABIInfo
272+
273+
.. c:member:: uint8_t abiinfo_major_version
274+
275+
The major version of :c:struct:`PyABIInfo`. Can be set to:
276+
277+
* ``0`` to skip all checking, or
278+
* ``1`` to specify this version of :c:struct:`!PyABIInfo`.
279+
280+
.. c:member:: uint8_t abiinfo_minor_version
281+
282+
The major version of :c:struct:`PyABIInfo`.
283+
Must be set to ``0``; larger values are reserved for backwards-compatible
284+
future versions of :c:struct:`!PyABIInfo`.
285+
286+
.. c:member:: uint16_t flags
287+
288+
.. c:namespace:: NULL
289+
290+
This field is usually set to the following macro:
291+
292+
.. c:macro:: PyABIInfo_DEFAULT_FLAGS
293+
294+
Default flags, based on current values of macros such as
295+
:c:macro:`Py_LIMITED_API` and :c:macro:`Py_GIL_DISABLED`.
296+
297+
Alternately, the field can be set to to the following flags, combined
298+
by bitwise OR.
299+
Unused bits must be set to zero.
300+
301+
ABI variant -- one of:
302+
303+
.. c:macro:: PyABIInfo_STABLE
304+
305+
Specifies that the stable ABI is used.
306+
307+
.. c:macro:: PyABIInfo_INTERNAL
308+
309+
Specifies ABI specific to a particular build of CPython.
310+
Internal use only.
311+
312+
Free-threading compatibility -- one of:
313+
314+
.. c:macro:: PyABIInfo_FREETHREADED
315+
316+
Specifies ABI compatible with free-threading builds of CPython.
317+
(That is, ones compiled with :option:`--disable-gil`; with ``t``
318+
in :py:data:`sys.abiflags`)
319+
320+
.. c:macro:: PyABIInfo_GIL
321+
322+
Specifies ABI compatible with non-free-threading builds of CPython
323+
(ones compiled *without* :option:`--disable-gil`).
324+
325+
.. c:member:: uint32_t build_version
326+
327+
The version of the Python headers used to build the code, in the format
328+
used by :c:macro:`PY_VERSION_HEX`.
329+
330+
This can be set to ``0`` to skip any checks related to this field.
331+
This option is meant mainly for projects that do not use the CPython
332+
headers directly, and do not emulate a specific version of them.
333+
334+
.. c:member:: uint32_t abi_version
335+
336+
The ABI version.
337+
338+
For the Stable ABI, this field should be the value of
339+
:c:macro:`Py_LIMITED_API`
340+
(except if :c:macro:`Py_LIMITED_API` is ``3``; use
341+
:c:expr:`Py_PACK_VERSION(3, 2)` in that case).
342+
343+
Otherwise, it should be set to :c:macro:`PY_VERSION_HEX`.
344+
345+
It can also be set to ``0`` to skip any checks related to this field.
346+
347+
.. c:namespace:: NULL
348+
349+
.. c:macro:: PyABIInfo_DEFAULT_ABI_VERSION
350+
351+
The value that should be used for this field, based on current
352+
values of macros such as :c:macro:`Py_LIMITED_API`,
353+
:c:macro:`PY_VERSION_HEX` and :c:macro:`Py_GIL_DISABLED`.
354+
355+
.. versionadded:: next
356+
357+
202358
.. _limited-api-list:
203359

204360
Contents of Limited API

‎Doc/data/stable_abi.dat

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Doc/using/configure.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ General Options
293293

294294
.. option:: --disable-gil
295295

296+
.. c:macro:: Py_GIL_DISABLED
297+
:no-typesetting:
298+
296299
Enables support for running Python without the :term:`global interpreter
297300
lock` (GIL): free threading build.
298301

‎Doc/whatsnew/3.15.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,11 @@ New features
670670
a string. See the documentation for caveats.
671671
(Contributed by Petr Viktorin in :gh:`131510`)
672672

673+
* Add API for checking an extension module's ABI compatibility:
674+
:c:data:`Py_mod_abi`, :c:func:`PyABIInfo_Check`, :c:macro:`PyABIInfo_VAR`
675+
and :c:data:`Py_mod_abi`.
676+
(Contributed by Petr Viktorin in :gh:`137210`)
677+
673678

674679
Porting to Python 3.15
675680
----------------------

‎Include/cpython/modsupport.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,15 @@ typedef struct _PyArg_Parser {
2424

2525
PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
2626
struct _PyArg_Parser *, ...);
27+
28+
#ifdef Py_BUILD_CORE
29+
// Internal; defined here to avoid explicitly including pycore_modsupport.h
30+
#define _Py_INTERNAL_ABI_SLOT \
31+
{Py_mod_abi, (void*) &(PyABIInfo) { \
32+
.abiinfo_major_version = 1, \
33+
.abiinfo_minor_version = 0, \
34+
.flags = PyABIInfo_INTERNAL, \
35+
.build_version = PY_VERSION_HEX, \
36+
.abi_version = PY_VERSION_HEX }} \
37+
///////////////////////////////////////////////////////
38+
#endif

‎Include/internal/pycore_unicodeobject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ extern int _PyUnicode_FormatAdvancedWriter(
8282
Py_ssize_t start,
8383
Py_ssize_t end);
8484

85+
/* PyUnicodeWriter_Format, with va_list instead of `...` */
86+
extern int _PyUnicodeWriter_FormatV(
87+
PyUnicodeWriter *writer,
88+
const char *format,
89+
va_list vargs);
90+
8591
/* --- UTF-7 Codecs ------------------------------------------------------- */
8692

8793
extern PyObject* _PyUnicode_EncodeUTF7(

‎Include/modsupport.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,72 @@ PyAPI_FUNC(PyObject *) PyModule_FromDefAndSpec2(PyModuleDef *def,
134134

135135
#endif /* New in 3.5 */
136136

137+
/* ABI info & checking (new in 3.15) */
138+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030f0000
139+
typedef struct PyABIInfo {
140+
uint8_t abiinfo_major_version;
141+
uint8_t abiinfo_minor_version;
142+
uint16_t flags;
143+
uint32_t build_version;
144+
uint32_t abi_version;
145+
} PyABIInfo;
146+
#define PyABIInfo_STABLE 0x0001
147+
#define PyABIInfo_GIL 0x0002
148+
#define PyABIInfo_FREETHREADED 0x0004
149+
#define PyABIInfo_INTERNAL 0x0008
150+
151+
#define PyABIInfo_FREETHREADING_AGNOSTIC (PyABIInfo_GIL|PyABIInfo_FREETHREADED)
152+
153+
PyAPI_FUNC(int) PyABIInfo_Check(PyABIInfo *info, const char *module_name);
154+
155+
// Define the defaults
156+
#ifdef Py_LIMITED_API
157+
#define _PyABIInfo_DEFAULT_FLAG_STABLE PyABIInfo_STABLE
158+
#if Py_LIMITED_API == 3
159+
#define PyABIInfo_DEFAULT_ABI_VERSION _Py_PACK_VERSION(3, 2)
160+
#else
161+
#define PyABIInfo_DEFAULT_ABI_VERSION Py_LIMITED_API
162+
#endif
163+
#else
164+
#define _PyABIInfo_DEFAULT_FLAG_STABLE 0
165+
#define PyABIInfo_DEFAULT_ABI_VERSION PY_VERSION_HEX
166+
#endif
167+
#if defined(Py_LIMITED_API) && defined(_Py_OPAQUE_PYOBJECT)
168+
#define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_FREETHREADING_AGNOSTIC
169+
#elif defined(Py_GIL_DISABLED)
170+
#define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_FREETHREADED
171+
#else
172+
#define _PyABIInfo_DEFAULT_FLAG_FT PyABIInfo_GIL
173+
#endif
174+
#if defined(Py_BUILD_CORE)
175+
#define _PyABIInfo_DEFAULT_FLAG_INTERNAL PyABIInfo_INTERNAL
176+
#else
177+
#define _PyABIInfo_DEFAULT_FLAG_INTERNAL 0
178+
#endif
179+
180+
#define PyABIInfo_DEFAULT_FLAGS ( \
181+
_PyABIInfo_DEFAULT_FLAG_STABLE \
182+
| _PyABIInfo_DEFAULT_FLAG_FT \
183+
| _PyABIInfo_DEFAULT_FLAG_INTERNAL \
184+
) \
185+
/////////////////////////////////////////////////////////
186+
187+
#define _PyABIInfo_DEFAULT() { \
188+
1, 0, \
189+
PyABIInfo_DEFAULT_FLAGS, \
190+
PY_VERSION_HEX, \
191+
PyABIInfo_DEFAULT_ABI_VERSION } \
192+
/////////////////////////////////////////////////////////
193+
194+
#define PyABIInfo_VAR(NAME) \
195+
static PyABIInfo NAME = _PyABIInfo_DEFAULT;
196+
197+
#undef _PyABIInfo_DEFAULT_STABLE
198+
#undef _PyABIInfo_DEFAULT_FT
199+
#undef _PyABIInfo_DEFAULT_INTERNAL
200+
201+
#endif /* ABI info (new in 3.15) */
202+
137203
#ifndef Py_LIMITED_API
138204
# define Py_CPYTHON_MODSUPPORT_H
139205
# include "cpython/modsupport.h"

‎Include/moduleobject.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,13 @@ struct PyModuleDef_Slot {
8181
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
8282
# define Py_mod_gil 4
8383
#endif
84+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
85+
# define Py_mod_abi 5
86+
#endif
8487

8588

8689
#ifndef Py_LIMITED_API
87-
#define _Py_mod_LAST_SLOT 4
90+
#define _Py_mod_LAST_SLOT 5
8891
#endif
8992

9093
#endif /* New in 3.5 */

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /