-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[C API] Convert PyTuple_GET_ITEM() macro to a static inline function #85250
Comments
PyTuple_GET_ITEM() can be abused to access directly the PyTupleObject.ob_item member: PyObject **items = &PyTuple_GET_ITEM(0); Giving a direct access to an array or PyObject* (PyObject**) is causing issues with other Python implementations, like PyPy, which don't use PyObject internally. I propose to convert the PyTuple_GET_ITEM() and PyList_GET_ITEM() macros to static inline functions to disallow that. |
The PR 21059 breaks Cython. I reported the issue to Cython upstream: numpy is also affected: code generated by Cython (numpy/random/_mt19937.c) contains the issue. |
PySequence_Fast_ITEMS() must also be deprecated since it also gives a direct access to PyTupleObject.ob_item and PyListObject.ob_item members (PyObject**). PySequence_Fast_GET_ITEM() should be used instead. |
PySequence_Fast_ITEMS() is used in numpy at 7 lines: numpy/core/src/common/ufunc_override.c:118: *out_objs = PySequence_Fast_ITEMS(seq); --- PyUFuncOverride_GetOutObjects(PyObject *kwds, PyObject **out_kwd_obj, PyObject ***out_objs) => PyObject** is part of the numpy C API (it's even a pointer to a PyObject** array)! numpy/core/src/multiarray/arrayfunction_override.c:80: PyObject **items = PySequence_Fast_ITEMS(relevant_args); static int
get_implementing_args_and_methods(PyObject *relevant_args,
PyObject **implementing_args,
PyObject **methods)
{
int num_implementing_args = 0;
Py_ssize_t i;
int j;
PyObject **items = PySequence_Fast_ITEMS(relevant_args);
Py_ssize_t length = PySequence_Fast_GET_SIZE(relevant_args);
for (i = 0; i < length; i++) {
int new_class = 1;
PyObject *argument = items[i]; => here PySequence_Fast_GET_ITEM() can be used instead. numpy/core/src/multiarray/arrayfunction_override.c:167: PyObject **items = PySequence_Fast_ITEMS(types); |
I'm wondering – if the intention is to help other implementations, then why do we need to break extensions in *CPython* for that? In CPython, this usage seems perfectly valid with the current data structure. If that ever changes, we can still make this change as well, but do you really see the internal layout of tuples change at some point? (Lists are a different case, I'd say, but tuples?) |
The long rationale is explained in PEP-620: PyTupleObject and PyListObject structures must become opaque. Also, later, these structures may change to be more efficient. |
Tuples? Really? Ok, quoting PEP-620:
I honestly think the reason for that might simply be that there's not so much to improve for tuples.
I certainly understand that that is a problem, especially if "PyObject" may change in the future. And this is essentially what the current "PyTuple_GET_ITEM()" macro does in a binary module. Should we also turn "_PyTuple_ITEMS()" into a public inline function then to make up for the loss of the "&PyTuple_GET_ITEM(t, 0)" pattern? It would make it explicit what is intended. I think that should be our main goal in the CPython side. |
See "(PEP-620) C API for efficient loop iterating on a sequence of PyObject** or other C types" thread on python-dev: |
The PEP-620 is still a draft. I prefer to work on other C API changes before coming back to this change which may break many C extensions. I failed finding time to design an API to expose a PyObject** array "view" with a function to release/destroy the view. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: