diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 8e66576b5c5f00..95409d48c0da02 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/gc.c b/Modules/_testcapi/gc.c new file mode 100644 index 00000000000000..829200ad12cd3c --- /dev/null +++ b/Modules/_testcapi/gc.c @@ -0,0 +1,344 @@ +#include "parts.h" + +static PyObject* +test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + int orig_enabled = PyGC_IsEnabled(); + const char* msg = "ok"; + int old_state; + + old_state = PyGC_Enable(); + msg = "Enable(1)"; + if (old_state != orig_enabled) { + goto failed; + } + msg = "IsEnabled(1)"; + if (!PyGC_IsEnabled()) { + goto failed; + } + + old_state = PyGC_Disable(); + msg = "disable(2)"; + if (!old_state) { + goto failed; + } + msg = "IsEnabled(2)"; + if (PyGC_IsEnabled()) { + goto failed; + } + + old_state = PyGC_Enable(); + msg = "enable(3)"; + if (old_state) { + goto failed; + } + msg = "IsEnabled(3)"; + if (!PyGC_IsEnabled()) { + goto failed; + } + + if (!orig_enabled) { + old_state = PyGC_Disable(); + msg = "disable(4)"; + if (old_state) { + goto failed; + } + msg = "IsEnabled(4)"; + if (PyGC_IsEnabled()) { + goto failed; + } + } + + Py_RETURN_NONE; + +failed: + /* Try to clean up if we can. */ + if (orig_enabled) { + PyGC_Enable(); + } else { + PyGC_Disable(); + } + PyErr_Format(PyExc_ValueError, "GC control failed in %s", msg); + return NULL; +} + +static PyObject * +without_gc(PyObject *Py_UNUSED(self), PyObject *obj) +{ + PyTypeObject *tp = (PyTypeObject*)obj; + if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj); + } + if (PyType_IS_GC(tp)) { + // Don't try this at home, kids: + tp->tp_flags -= Py_TPFLAGS_HAVE_GC; + tp->tp_free = PyObject_Del; + tp->tp_traverse = NULL; + tp->tp_clear = NULL; + } + assert(!PyType_IS_GC(tp)); + return Py_NewRef(obj); +} + +static void +slot_tp_del(PyObject *self) +{ + PyObject *del, *res; + + /* Temporarily resurrect the object. */ + assert(Py_REFCNT(self) == 0); + Py_SET_REFCNT(self, 1); + + /* Save the current exception, if any. */ + PyObject *exc = PyErr_GetRaisedException(); + + PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); + if (tp_del == NULL) { + PyErr_WriteUnraisable(NULL); + PyErr_SetRaisedException(exc); + return; + } + /* Execute __del__ method, if any. */ + del = _PyType_Lookup(Py_TYPE(self), tp_del); + Py_DECREF(tp_del); + if (del != NULL) { + res = PyObject_CallOneArg(del, self); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + } + + /* Restore the saved exception. */ + PyErr_SetRaisedException(exc); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(Py_REFCNT(self) > 0); + Py_SET_REFCNT(self, Py_REFCNT(self) - 1); + if (Py_REFCNT(self) == 0) { + /* this is the normal path out */ + return; + } + + /* __del__ resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReferenceNoTotal(self); + Py_SET_REFCNT(self, refcnt); + } + assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); +} + +static PyObject * +with_tp_del(PyObject *self, PyObject *args) +{ + PyObject *obj; + PyTypeObject *tp; + + if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj)) + return NULL; + tp = (PyTypeObject *) obj; + if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "heap type expected, got %R", obj); + return NULL; + } + tp->tp_del = slot_tp_del; + return Py_NewRef(obj); +} + + +struct gc_visit_state_basic { + PyObject *target; + int found; +}; + +static int +gc_visit_callback_basic(PyObject *obj, void *arg) +{ + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; + if (obj == state->target) { + state->found = 1; + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + PyObject *obj; + struct gc_visit_state_basic state; + + obj = PyList_New(0); + if (obj == NULL) { + return NULL; + } + state.target = obj; + state.found = 0; + + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + +typedef struct { + PyObject_HEAD +} ObjExtraData; + +static PyObject * +obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + size_t extra_size = sizeof(PyObject *); + PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size); + if (obj == NULL) { + return PyErr_NoMemory(); + } + PyObject_GC_Track(obj); + return obj; +} + +static PyObject ** +obj_extra_data_get_extra_storage(PyObject *self) +{ + return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize); +} + +static PyObject * +obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + if (!value) { + Py_RETURN_NONE; + } + return Py_NewRef(value); +} + +static int +obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + if (newval) { + *extra_storage = Py_NewRef(newval); + } + return 0; +} + +static PyGetSetDef obj_extra_data_getset[] = { + {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL}, + {NULL} +}; + +static int +obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + Py_VISIT(value); + return 0; +} + +static int +obj_extra_data_clear(PyObject *self) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + return 0; +} + +static void +obj_extra_data_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + obj_extra_data_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot ObjExtraData_Slots[] = { + {Py_tp_getset, obj_extra_data_getset}, + {Py_tp_dealloc, obj_extra_data_dealloc}, + {Py_tp_traverse, obj_extra_data_traverse}, + {Py_tp_clear, obj_extra_data_clear}, + {Py_tp_new, obj_extra_data_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec ObjExtraData_TypeSpec = { + .name = "_testcapi.ObjExtraData", + .basicsize = sizeof(ObjExtraData), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .slots = ObjExtraData_Slots, +}; + +static PyMethodDef test_methods[] = { + {"test_gc_control", test_gc_control, METH_NOARGS}, + {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, + {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, + {"without_gc", without_gc, METH_O, NULL}, + {"with_tp_del", with_tp_del, METH_VARARGS, NULL}, + {NULL} +}; + +int _PyTestCapi_Init_GC(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec( + mod, &ObjExtraData_TypeSpec, NULL); + if (ObjExtraData_Type == 0) { + return -1; + } + int ret = PyModule_AddType(mod, (PyTypeObject*)ObjExtraData_Type); + Py_DECREF(ObjExtraData_Type); + if (ret < 0) { + return ret; + } + + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index 663d4f2255de88..d1991ac6b464f2 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -41,6 +41,7 @@ int _PyTestCapi_Init_Code(PyObject *module); int _PyTestCapi_Init_Buffer(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module); +int _PyTestCapi_Init_GC(PyObject *mod); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 79ab7d3f5555c2..c29d29c4791134 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -154,68 +154,6 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored)) #endif } -static PyObject* -test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - int orig_enabled = PyGC_IsEnabled(); - const char* msg = "ok"; - int old_state; - - old_state = PyGC_Enable(); - msg = "Enable(1)"; - if (old_state != orig_enabled) { - goto failed; - } - msg = "IsEnabled(1)"; - if (!PyGC_IsEnabled()) { - goto failed; - } - - old_state = PyGC_Disable(); - msg = "disable(2)"; - if (!old_state) { - goto failed; - } - msg = "IsEnabled(2)"; - if (PyGC_IsEnabled()) { - goto failed; - } - - old_state = PyGC_Enable(); - msg = "enable(3)"; - if (old_state) { - goto failed; - } - msg = "IsEnabled(3)"; - if (!PyGC_IsEnabled()) { - goto failed; - } - - if (!orig_enabled) { - old_state = PyGC_Disable(); - msg = "disable(4)"; - if (old_state) { - goto failed; - } - msg = "IsEnabled(4)"; - if (PyGC_IsEnabled()) { - goto failed; - } - } - - Py_RETURN_NONE; - -failed: - /* Try to clean up if we can. */ - if (orig_enabled) { - PyGC_Enable(); - } else { - PyGC_Disable(); - } - PyErr_Format(TestError, "GC control failed in %s", msg); - return NULL; -} - static PyObject* test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -1627,95 +1565,6 @@ restore_crossinterp_data(PyObject *self, PyObject *args) return _PyCrossInterpreterData_NewObject(data); } -static void -slot_tp_del(PyObject *self) -{ - PyObject *del, *res; - - /* Temporarily resurrect the object. */ - assert(Py_REFCNT(self) == 0); - Py_SET_REFCNT(self, 1); - - /* Save the current exception, if any. */ - PyObject *exc = PyErr_GetRaisedException(); - - PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); - if (tp_del == NULL) { - PyErr_WriteUnraisable(NULL); - PyErr_SetRaisedException(exc); - return; - } - /* Execute __del__ method, if any. */ - del = _PyType_Lookup(Py_TYPE(self), tp_del); - Py_DECREF(tp_del); - if (del != NULL) { - res = PyObject_CallOneArg(del, self); - if (res == NULL) - PyErr_WriteUnraisable(del); - else - Py_DECREF(res); - } - - /* Restore the saved exception. */ - PyErr_SetRaisedException(exc); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(Py_REFCNT(self) > 0); - Py_SET_REFCNT(self, Py_REFCNT(self) - 1); - if (Py_REFCNT(self) == 0) { - /* this is the normal path out */ - return; - } - - /* __del__ resurrected it! Make it look like the original Py_DECREF - * never happened. - */ - { - Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReferenceNoTotal(self); - Py_SET_REFCNT(self, refcnt); - } - assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); -} - -static PyObject * -with_tp_del(PyObject *self, PyObject *args) -{ - PyObject *obj; - PyTypeObject *tp; - - if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj)) - return NULL; - tp = (PyTypeObject *) obj; - if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, - "heap type expected, got %R", obj); - return NULL; - } - tp->tp_del = slot_tp_del; - return Py_NewRef(obj); -} - -static PyObject * -without_gc(PyObject *Py_UNUSED(self), PyObject *obj) -{ - PyTypeObject *tp = (PyTypeObject*)obj; - if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { - return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj); - } - if (PyType_IS_GC(tp)) { - // Don't try this at home, kids: - tp->tp_flags -= Py_TPFLAGS_HAVE_GC; - tp->tp_free = PyObject_Del; - tp->tp_traverse = NULL; - tp->tp_clear = NULL; - } - assert(!PyType_IS_GC(tp)); - return Py_NewRef(obj); -} - static PyMethodDef ml; static PyObject * @@ -3342,165 +3191,6 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } -struct gc_visit_state_basic { - PyObject *target; - int found; -}; - -static int -gc_visit_callback_basic(PyObject *obj, void *arg) -{ - struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; - if (obj == state->target) { - state->found = 1; - return 0; - } - return 1; -} - -static PyObject * -test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), - PyObject *Py_UNUSED(ignored)) -{ - PyObject *obj; - struct gc_visit_state_basic state; - - obj = PyList_New(0); - if (obj == NULL) { - return NULL; - } - state.target = obj; - state.found = 0; - - PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); - Py_DECREF(obj); - if (!state.found) { - PyErr_SetString( - PyExc_AssertionError, - "test_gc_visit_objects_basic: Didn't find live list"); - return NULL; - } - Py_RETURN_NONE; -} - -static int -gc_visit_callback_exit_early(PyObject *obj, void *arg) - { - int *visited_i = (int *)arg; - (*visited_i)++; - if (*visited_i == 2) { - return 0; - } - return 1; -} - -static PyObject * -test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), - PyObject *Py_UNUSED(ignored)) -{ - int visited_i = 0; - PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); - if (visited_i != 2) { - PyErr_SetString( - PyExc_AssertionError, - "test_gc_visit_objects_exit_early: did not exit when expected"); - } - Py_RETURN_NONE; -} - -typedef struct { - PyObject_HEAD -} ObjExtraData; - -static PyObject * -obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - size_t extra_size = sizeof(PyObject *); - PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size); - if (obj == NULL) { - return PyErr_NoMemory(); - } - PyObject_GC_Track(obj); - return obj; -} - -static PyObject ** -obj_extra_data_get_extra_storage(PyObject *self) -{ - return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize); -} - -static PyObject * -obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored)) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - PyObject *value = *extra_storage; - if (!value) { - Py_RETURN_NONE; - } - return Py_NewRef(value); -} - -static int -obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored)) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - Py_CLEAR(*extra_storage); - if (newval) { - *extra_storage = Py_NewRef(newval); - } - return 0; -} - -static PyGetSetDef obj_extra_data_getset[] = { - {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL}, - {NULL} -}; - -static int -obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - PyObject *value = *extra_storage; - Py_VISIT(value); - return 0; -} - -static int -obj_extra_data_clear(PyObject *self) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - Py_CLEAR(*extra_storage); - return 0; -} - -static void -obj_extra_data_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - obj_extra_data_clear(self); - tp->tp_free(self); - Py_DECREF(tp); -} - -static PyType_Slot ObjExtraData_Slots[] = { - {Py_tp_getset, obj_extra_data_getset}, - {Py_tp_dealloc, obj_extra_data_dealloc}, - {Py_tp_traverse, obj_extra_data_traverse}, - {Py_tp_clear, obj_extra_data_clear}, - {Py_tp_new, obj_extra_data_new}, - {Py_tp_free, PyObject_GC_Del}, - {0, NULL}, -}; - -static PyType_Spec ObjExtraData_TypeSpec = { - .name = "_testcapi.ObjExtraData", - .basicsize = sizeof(ObjExtraData), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .slots = ObjExtraData_Slots, -}; - struct atexit_data { int called; }; @@ -3538,7 +3228,6 @@ static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, {"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS}, - {"test_gc_control", test_gc_control, METH_NOARGS}, {"test_list_api", test_list_api, METH_NOARGS}, {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, {"dict_getitem_knownhash", dict_getitem_knownhash, METH_VARARGS}, @@ -3590,7 +3279,6 @@ static PyMethodDef TestMethods[] = { METH_VARARGS | METH_KEYWORDS}, {"get_crossinterp_data", get_crossinterp_data, METH_VARARGS}, {"restore_crossinterp_data", restore_crossinterp_data, METH_VARARGS}, - {"with_tp_del", with_tp_del, METH_VARARGS}, {"create_cfunction", create_cfunction, METH_NOARGS}, {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS, PyDoc_STR("set_error_class(error_class) -> None")}, @@ -3641,7 +3329,6 @@ static PyMethodDef TestMethods[] = { {"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL}, {"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS}, {"pynumber_tobase", pynumber_tobase, METH_VARARGS}, - {"without_gc", without_gc, METH_O}, {"test_set_type_size", test_set_type_size, METH_NOARGS}, {"test_py_clear", test_py_clear, METH_NOARGS}, {"test_py_setref", test_py_setref, METH_NOARGS}, @@ -3675,8 +3362,6 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, - {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, - {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, {"test_atexit", test_atexit, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; @@ -4223,17 +3908,6 @@ PyInit__testcapi(void) Py_INCREF(&MethStatic_Type); PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type); - PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec( - m, &ObjExtraData_TypeSpec, NULL); - if (ObjExtraData_Type == 0) { - return NULL; - } - int ret = PyModule_AddType(m, (PyTypeObject*)ObjExtraData_Type); - Py_DECREF(ObjExtraData_Type); - if (ret < 0) { - return NULL; - } - PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX)); PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN)); PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX)); @@ -4327,6 +4001,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Immortal(m) < 0) { return NULL; } + if (_PyTestCapi_Init_GC(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 350f97f8ff41aa..3db9426d1a25ff 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -113,6 +113,7 @@ + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index af80f1eebb3c4d..8df4874659fa1c 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -66,6 +66,9 @@ Source Files + + Source Files + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy