#define Py_LIMITED_API 0x030f0000 #include "parts.h" PyABIInfo_VAR(abi_info); /* Define a bunch of (mostly nonsensical) functions to put in slots, so * Lib/test/test_capi/test_slots.py can verify they've been assigned to * the right slots. * This module is full of "magic constants" which simply need to match * between the C and Python part of the tests. */ // getbufferproc: export buffer; increment a counter static int demo_getbuffer(PyObject *exporter, Py_buffer *view, int flags) { Py_INCREF(exporter); // PyObject_GetTypeData & Py_TYPE: safe on non-subclassable type int *data = PyObject_GetTypeData(exporter, Py_TYPE(exporter)); if (!data) { return -1; } (*data)++; return PyBuffer_FillInfo(view, exporter, "buf", 4, 1, flags); } // releasebufferproc: release buffer; decrement a counter static void demo_releasebuffer(PyObject *exporter, Py_buffer *view) { Py_DECREF(exporter); // PyObject_GetTypeData & Py_TYPE: safe on non-subclassable type int *data = PyObject_GetTypeData(exporter, Py_TYPE(exporter)); if (!data) { PyErr_WriteUnraisable(exporter); return; } (*data)--; return; } // objobjargproc: raise KeyError static int demo_ass_subscript(PyObject *o, PyObject *key, PyObject *v) { PyErr_Format(PyExc_KeyError, "I don't like that key"); return -1; } // lenfunc: report 456 static Py_ssize_t demo_length(PyObject *o) { return (Py_ssize_t)456; } // binaryfunc; return constant value static PyObject *binop_123(PyObject* a, PyObject *b) { return PyLong_FromLong(123); } static PyObject *binop_234(PyObject* a, PyObject *b) { return PyLong_FromLong(234); } static PyObject *binop_345(PyObject* a, PyObject *b) { return PyLong_FromLong(345); } static PyObject *binop_456(PyObject* a, PyObject *b) { return PyLong_FromLong(456); } static PyObject *binop_567(PyObject* a, PyObject *b) { return PyLong_FromLong(567); } static PyObject *binop_678(PyObject* a, PyObject *b) { return PyLong_FromLong(678); } static PyObject * type_from_slots(PyObject* module, PyObject *args) { char *case_name; if (!PyArg_ParseTuple(args, "s", &case_name)) { return NULL; } #define CASE(NAME) \ if (strcmp(case_name, NAME) == 0) { \ return PyType_FromSlots((PySlot[]) { \ PySlot_DATA(Py_tp_name, "_testlimitedcapi.MyType"), \ PySlot_DATA(Py_tp_module, module), \ ///////////////////////////////////////////////////////////////////////// #define ENDCASE() \ PySlot_END \ }); \ } \ ///////////////////////////////////////////////////////////////////////// CASE("basic") ENDCASE() CASE("foreign_slot") PySlot_DATA(Py_mod_name, "this is not a module"), ENDCASE() CASE("basicsize") PySlot_SIZE(Py_tp_basicsize, 256), ENDCASE() CASE("extra_basicsize") PySlot_SIZE(Py_tp_extra_basicsize, 256), ENDCASE() CASE("itemsize") PySlot_SIZE(Py_tp_itemsize, 16), ENDCASE() CASE("flags") PySlot_UINT64(Py_tp_flags, Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_BASETYPE), ENDCASE() CASE("matmul_123") PySlot_FUNC(Py_nb_matrix_multiply, binop_123), ENDCASE() CASE("optional_end") {.sl_flags=PySlot_OPTIONAL}, ENDCASE() CASE("invalid") {.sl_id=Py_slot_invalid}, ENDCASE() CASE("invalid_fbad") {.sl_id=0xfbad}, ENDCASE() CASE("optional_invalid") {.sl_id=Py_slot_invalid, .sl_flags=PySlot_OPTIONAL}, PySlot_SIZE(Py_tp_extra_basicsize, 256), ENDCASE() CASE("optional_invalid_fbad") {.sl_id=0xfbad, .sl_flags=PySlot_OPTIONAL}, PySlot_SIZE(Py_tp_extra_basicsize, 256), ENDCASE() CASE("old_slot_numbers") PySlot_FUNC(1, demo_getbuffer), PySlot_FUNC(2, demo_releasebuffer), PySlot_FUNC(3, demo_ass_subscript), PySlot_FUNC(4, demo_length), PySlot_SIZE(Py_tp_extra_basicsize, sizeof(int)), PySlot_STATIC_DATA(Py_tp_members, ((PyMemberDef[]) { {"buf_counter", Py_T_INT, 0, Py_READONLY | Py_RELATIVE_OFFSET}, {NULL}, })), ENDCASE() CASE("new_slot_numbers") PySlot_FUNC(88, demo_getbuffer), PySlot_FUNC(89, demo_releasebuffer), PySlot_FUNC(90, demo_ass_subscript), PySlot_FUNC(91, demo_length), PySlot_SIZE(Py_tp_extra_basicsize, sizeof(int)), PySlot_STATIC_DATA(Py_tp_members, ((PyMemberDef[]) { {"buf_counter", Py_T_INT, 0, Py_READONLY | Py_RELATIVE_OFFSET}, {NULL}, })), ENDCASE() CASE("nonstatic_tp_members") PySlot_SIZE(Py_tp_extra_basicsize, sizeof(int)), PySlot_DATA(Py_tp_members, ((PyMemberDef[]) { {"buf_counter", Py_T_INT, 0, Py_READONLY | Py_RELATIVE_OFFSET}, {NULL}, })), ENDCASE() CASE("intptr_flags_macro") PySlot_PTR(Py_tp_flags, (void*)(intptr_t)Py_TPFLAGS_IMMUTABLETYPE), ENDCASE() CASE("intptr_flags_struct") {.sl_id=Py_tp_flags, .sl_flags=PySlot_INTPTR, .sl_ptr=(void*)(intptr_t)Py_TPFLAGS_IMMUTABLETYPE, }, ENDCASE() CASE("intptr_static") PySlot_SIZE(Py_tp_extra_basicsize, sizeof(int)), PySlot_PTR_STATIC(Py_tp_members, ((PyMemberDef[]) { {"attribute", Py_T_INT, 0, Py_READONLY | Py_RELATIVE_OFFSET}, {NULL}, })), ENDCASE() CASE("nested") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_subtract, binop_234), PySlot_END, })), ENDCASE() CASE("nested_max") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_subtract, binop_234), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_multiply, binop_345), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_true_divide, binop_456), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_remainder, binop_567), PySlot_END })), PySlot_END, })), PySlot_END, })), PySlot_END, })), ENDCASE() CASE("nested_over_limit") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_subtract, binop_234), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_multiply, binop_345), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_true_divide, binop_456), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_remainder, binop_567), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_xor, binop_678), PySlot_END })), PySlot_END })), PySlot_END, })), PySlot_END, })), PySlot_END, })), ENDCASE() CASE("nested_old") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_tp_slots, ((PyType_Slot[]) { {Py_nb_subtract, binop_234}, {0}, })), ENDCASE() CASE("nested_old_max") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_tp_slots, ((PyType_Slot[]) { {Py_nb_subtract, binop_234}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_multiply, binop_345}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_true_divide, binop_456}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_remainder, binop_567}, {0}, })}, {0}, })}, {0}, })}, {0}, })), ENDCASE() CASE("nested_old_over_limit") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_tp_slots, ((PyType_Slot[]) { {Py_nb_subtract, binop_234}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_multiply, binop_345}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_true_divide, binop_456}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_remainder, binop_567}, {Py_tp_slots, ((PyType_Slot[]) { {Py_nb_xor, binop_678}, {0}, })}, {0}, })}, {0}, })}, {0}, })}, {0}, })), ENDCASE() CASE("nested_pingpong") PySlot_FUNC(Py_nb_add, binop_123), PySlot_DATA(Py_tp_slots, ((PyType_Slot[]) { {Py_nb_subtract, binop_234}, {Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_multiply, binop_345), PySlot_DATA(Py_tp_slots, ((PyType_Slot[]) { {Py_nb_true_divide, binop_456}, {Py_slot_subslots, ((PySlot[]) { PySlot_FUNC(Py_nb_remainder, binop_567), PySlot_END })}, {0}, })), PySlot_END, })}, {0}, })), ENDCASE() CASE("repeat_add") PySlot_FUNC(Py_nb_add, binop_123), PySlot_FUNC(Py_nb_add, binop_456), ENDCASE() CASE("repeat_module") PySlot_DATA(Py_tp_module, Py_True), PySlot_DATA(Py_tp_module, Py_False), ENDCASE() #undef CASE #undef ENDCASE PyErr_Format(PyExc_SystemError, "bad case: %s", case_name); return NULL; } static PyObject * type_from_null_slot(PyObject* module, PyObject *args) { long slot_number; if (!PyArg_ParseTuple(args, "l", &slot_number)) { return NULL; } return PyType_FromSlots((PySlot[]) { PySlot_DATA(Py_tp_name, "_testlimitedcapi.MyType"), PySlot_DATA(Py_tp_module, module), PySlot_PTR_STATIC((uint16_t)slot_number, NULL), PySlot_END }); } static PyObject * type_from_null_spec_slot(PyObject* Py_UNUSED(module), PyObject *args) { long slot_number; if (!PyArg_ParseTuple(args, "l", &slot_number)) { return NULL; } return PyType_FromSpec(&(PyType_Spec) { .name = "_testlimitedcapi.MyType", .slots = (PyType_Slot[]) { {slot_number, NULL}, {0}, }, }); } static PyObject * demo_create(PyObject *spec, PyModuleDef *def) { assert(def == NULL); return Py_NewRef(spec); } static int demo_exec(PyObject *mod) { return PyModule_AddStringConstant(mod, "exec_done", "yes"); } static PyMethodDef *TestMethods; static PyObject * module_from_slots(PyObject* Py_UNUSED(module), PyObject *args) { PyObject *spec; char *case_name; if (!PyArg_ParseTuple(args, "sO", &case_name, &spec)) { return NULL; } PyObject *mod = NULL; #define CASE(NAME) \ if (strcmp(case_name, NAME) == 0) { \ mod = PyModule_FromSlotsAndSpec((PySlot[]) { \ PySlot_DATA(Py_mod_abi, &abi_info), \ PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), \ ///////////////////////////////////////////////////////////////////////// #define ENDCASE() \ PySlot_END \ }, spec); \ } \ ///////////////////////////////////////////////////////////////////////// CASE("basic") ENDCASE() CASE("foreign_slot") PySlot_DATA(Py_tp_name, "this is not a type"), ENDCASE() CASE("state_size") PySlot_SIZE(Py_mod_state_size, 42), ENDCASE() CASE("multi_interp") PySlot_DATA(Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED), ENDCASE() CASE("exec") PySlot_FUNC(Py_mod_exec, demo_exec), ENDCASE() CASE("optional_end") {.sl_flags=PySlot_OPTIONAL}, ENDCASE() CASE("invalid") {.sl_id=Py_slot_invalid}, ENDCASE() CASE("invalid_fbad") {.sl_id=0xfbad}, ENDCASE() CASE("optional_invalid") {.sl_id=Py_slot_invalid, .sl_flags=PySlot_OPTIONAL}, PySlot_SIZE(Py_mod_exec, demo_exec), ENDCASE() CASE("optional_invalid_fbad") {.sl_id=0xfbad, .sl_flags=PySlot_OPTIONAL}, PySlot_SIZE(Py_mod_exec, demo_exec), ENDCASE() CASE("old_slot_numbers") // 1: see old_slot_number_create case PySlot_FUNC(2, demo_exec), PySlot_DATA(3, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED), // 4: see module_from_gil_slot function ENDCASE() CASE("new_slot_numbers") // 84: see new_slot_number_create case PySlot_FUNC(85, demo_exec), PySlot_FUNC(86, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED), // 87: see module_from_gil_slot function ENDCASE() CASE("old_slot_number_create") PySlot_FUNC(1, demo_create), ENDCASE() CASE("new_slot_number_create") PySlot_FUNC(84, demo_create), ENDCASE() CASE("nonstatic_mod_methods") PySlot_DATA(Py_mod_methods, TestMethods), ENDCASE() CASE("intptr_methods") PySlot_PTR_STATIC(Py_mod_methods, TestMethods), ENDCASE() CASE("nested") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_mod_doc, "doc"), PySlot_END, })), ENDCASE() CASE("nested_max") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_SIZE(Py_mod_state_size, 53), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_mod_doc, "doc"), PySlot_END })), PySlot_END, })), PySlot_END, })), PySlot_END, })), ENDCASE() CASE("nested_over_limit") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_SIZE(Py_mod_state_size, 53), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_mod_doc, "doc"), PySlot_DATA(Py_slot_subslots, ((PySlot[]) { PySlot_END })), PySlot_END })), PySlot_END, })), PySlot_END, })), PySlot_END, })), ENDCASE() CASE("nested_old") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_doc, "doc"}, {0}, })), ENDCASE() CASE("nested_old_max") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_state_size, (void*)(intptr_t)53}, {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_doc, "doc"}, {0}, })}, {0}, })}, {0}, })}, {0}, })), ENDCASE() CASE("nested_old_over_limit") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_state_size, (void*)(intptr_t)53}, {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_doc, "doc"}, {0}, })}, {0}, })}, {0}, })}, {0}, })}, {0}, })), ENDCASE() CASE("nested_pingpong") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_DATA(Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_mod_slots, ((PyModuleDef_Slot[]) { {Py_mod_state_size, (void*)(intptr_t)53}, {Py_slot_subslots, ((PySlot[]) { PySlot_DATA(Py_mod_doc, "doc"), PySlot_END })}, {0}, })), PySlot_END, })}, {0}, })), ENDCASE() CASE("repeat_create") PySlot_DATA(Py_mod_create, demo_create), PySlot_DATA(Py_mod_create, demo_create), PySlot_DATA(Py_mod_create, demo_create), ENDCASE() CASE("repeat_gil") PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), ENDCASE() CASE("repeat_exec") PySlot_FUNC(Py_mod_exec, demo_exec), PySlot_FUNC(Py_mod_exec, demo_exec), ENDCASE() #undef CASE #undef ENDCASE if (!mod) { if (!PyErr_Occurred()) { PyErr_Format(PyExc_SystemError, "bad case: %s", case_name); return NULL; } return NULL; } if (PyModule_Check(mod)) { Py_ssize_t size; if (PyModule_GetStateSize(mod, &size) < 0) { Py_DECREF(mod); return NULL; } if (PyModule_AddIntConstant(mod, "state_size", (long)size) < 0) { Py_DECREF(mod); return NULL; } if (PyModule_Exec(mod) < 0) { return NULL; } } return mod; } static PyObject * module_from_gil_slot(PyObject* Py_UNUSED(module), PyObject *args) { long slot_number; PyObject *spec; if (!PyArg_ParseTuple(args, "lO", &slot_number, &spec)) { return NULL; } return PyModule_FromSlotsAndSpec((PySlot[]) { PySlot_DATA(Py_mod_abi, &abi_info), PySlot_PTR_STATIC((uint16_t)slot_number, Py_MOD_GIL_NOT_USED), PySlot_END }, spec); } static PyObject * module_from_null_slot(PyObject* Py_UNUSED(module), PyObject *args) { long slot_number; PyObject *spec; if (!PyArg_ParseTuple(args, "lO", &slot_number, &spec)) { return NULL; } uint16_t maybe_gil_slot = Py_mod_gil; if ((slot_number == 4) || (slot_number == 87)) { // Do not repeat the GIL slot maybe_gil_slot = Py_slot_invalid; } return PyModule_FromSlotsAndSpec((PySlot[]) { PySlot_DATA(Py_mod_abi, &abi_info), PySlot_DATA(Py_mod_name, "mymod"), PySlot_PTR_STATIC((uint16_t)slot_number, NULL), { .sl_id=maybe_gil_slot, .sl_flags=PySlot_OPTIONAL, .sl_ptr=Py_MOD_GIL_NOT_USED, }, PySlot_END }, spec); } static PyMethodDef _TestMethods[] = { {"type_from_slots", type_from_slots, METH_VARARGS}, {"module_from_gil_slot", module_from_gil_slot, METH_VARARGS}, {"type_from_null_slot", type_from_null_slot, METH_VARARGS}, {"type_from_null_spec_slot", type_from_null_spec_slot, METH_VARARGS}, {"module_from_slots", module_from_slots, METH_VARARGS}, {"module_from_null_slot", module_from_null_slot, METH_VARARGS}, {NULL}, }; static PyMethodDef *TestMethods = _TestMethods; int _PyTestLimitedCAPI_Init_Slots(PyObject *m) { if (PyModule_AddFunctions(m, TestMethods) < 0) { return -1; } return 0; }