7272 pass
7373 */
7474
75- // Need limited C API version 3.15 for PyModExport
76- #define Py_LIMITED_API 0x030f0000
77-
78- // experimental: free-threaded build compatibility
79- // (for internal tests; this should only appear here in CPython alpha builds)
80- #define _Py_OPAQUE_PYOBJECT 0x030f0000
75+ // Target both flavors of the Stable ABI.
76+ // Both are set to version 3.15, which adds PyModExport
77+ // (When using a build tool, check if it has an option to set these
78+ // so they do not need to be defined in the source.)
79+ #define Py_LIMITED_API 0x030f0000 // abi3 (GIL-enabled builds)
80+ #define Py_TARGET_ABI3T 0x030f0000 // abi3t (free-threaded builds)
8181
8282
8383#include "Python.h"
@@ -156,6 +156,27 @@ Xxo_get_data(PyObject *self)
156156 return data ;
157157}
158158
159+ // A variant of Xxo_get_data to be used in the tp_traverse handler.
160+ // This function cannot have side effects (including reference count
161+ // manipulation, creating objects, and raising exceptions), and must not
162+ // call API functions that might have side effects.
163+ // See: https://docs.python.org/3.15/c-api/gcsupport.html#traversal
164+ static XxoObject_Data *
165+ Xxo_get_data_DuringGC (PyObject * self )
166+ {
167+ PyTypeObject * base ;
168+ PyType_GetBaseByToken_DuringGC (Py_TYPE (self ), & Xxo_Type_spec , & base );
169+ if (base == NULL ) {
170+ return NULL ;
171+ }
172+ xx_state * state = PyType_GetModuleState_DuringGC (base );
173+ if (state == NULL ) {
174+ return NULL ;
175+ }
176+ XxoObject_Data * data = PyObject_GetTypeData_DuringGC (self , state -> Xxo_Type );
177+ return data ;
178+ }
179+
159180// Xxo initialization
160181// This is the implementation of Xxo.__new__
161182static PyObject *
@@ -203,7 +224,7 @@ Xxo_traverse(PyObject *self, visitproc visit, void *arg)
203224 Py_VISIT (Py_TYPE (self ));
204225
205226 // Visit the attribute dict
206- XxoObject_Data * data = Xxo_get_data (self );
227+ XxoObject_Data * data = Xxo_get_data_DuringGC (self );
207228 if (data == NULL ) {
208229 return 0 ;
209230 }
@@ -535,7 +556,10 @@ xx_modexec(PyObject *m)
535556static int
536557xx_traverse (PyObject * module , visitproc visit , void * arg )
537558{
538- xx_state * state = PyModule_GetState (module );
559+ xx_state * state = PyModule_GetState_DuringGC (module );
560+ if (state == NULL ) {
561+ return 0 ;
562+ }
539563 Py_VISIT (state -> Xxo_Type );
540564 Py_VISIT (state -> Error_Type );
541565 return 0 ;
@@ -545,6 +569,9 @@ static int
545569xx_clear (PyObject * module )
546570{
547571 xx_state * state = PyModule_GetState (module );
572+ if (state == NULL ) {
573+ return 0 ;
574+ }
548575 Py_CLEAR (state -> Xxo_Type );
549576 Py_CLEAR (state -> Error_Type );
550577 return 0 ;
0 commit comments