mirror of https://github.com/python/cpython
gh-106168: PyTuple_SET_ITEM() now checks the index (#106164)
PyTuple_SET_ITEM() and PyList_SET_ITEM() now check the index argument with an assertion if Python is built in debug mode or is built with assertions. * list_extend() and _PyList_AppendTakeRef() now set the list size before calling PyList_SET_ITEM(). * PyStructSequence_GetItem() and PyStructSequence_SetItem() now check the index argument: must be lesser than REAL_SIZE(op). * PyStructSequence_GET_ITEM() and PyStructSequence_SET_ITEM() are now aliases to PyStructSequence_GetItem() and PyStructSequence_SetItem().
This commit is contained in:
parent
161012fc25
commit
3f8483cad2
|
@ -86,6 +86,10 @@ List Objects
|
||||||
Macro form of :c:func:`PyList_SetItem` without error checking. This is
|
Macro form of :c:func:`PyList_SetItem` without error checking. This is
|
||||||
normally only used to fill in new lists where there is no previous content.
|
normally only used to fill in new lists where there is no previous content.
|
||||||
|
|
||||||
|
Bounds checking is performed as an assertion if Python is built in
|
||||||
|
:ref:`debug mode <debug-build>` or :option:`with assertions
|
||||||
|
<--with-assertions>`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This macro "steals" a reference to *item*, and, unlike
|
This macro "steals" a reference to *item*, and, unlike
|
||||||
|
|
|
@ -89,6 +89,9 @@ Tuple Objects
|
||||||
Like :c:func:`PyTuple_SetItem`, but does no error checking, and should *only* be
|
Like :c:func:`PyTuple_SetItem`, but does no error checking, and should *only* be
|
||||||
used to fill in brand new tuples.
|
used to fill in brand new tuples.
|
||||||
|
|
||||||
|
Bounds checking is performed as an assertion if Python is built in
|
||||||
|
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This function "steals" a reference to *o*, and, unlike
|
This function "steals" a reference to *o*, and, unlike
|
||||||
|
@ -194,12 +197,17 @@ type.
|
||||||
.. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
|
.. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
|
||||||
|
|
||||||
Return the object at position *pos* in the struct sequence pointed to by *p*.
|
Return the object at position *pos* in the struct sequence pointed to by *p*.
|
||||||
No bounds checking is performed.
|
|
||||||
|
Bounds checking is performed as an assertion if Python is built in
|
||||||
|
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyStructSequence_GET_ITEM(PyObject *p, Py_ssize_t pos)
|
.. c:function:: PyObject* PyStructSequence_GET_ITEM(PyObject *p, Py_ssize_t pos)
|
||||||
|
|
||||||
Macro equivalent of :c:func:`PyStructSequence_GetItem`.
|
Alias to :c:func:`PyStructSequence_GetItem`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.13
|
||||||
|
Now implemented as an alias to :c:func:`PyStructSequence_GetItem`.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: void PyStructSequence_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)
|
.. c:function:: void PyStructSequence_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)
|
||||||
|
@ -208,6 +216,9 @@ type.
|
||||||
:c:func:`PyTuple_SET_ITEM`, this should only be used to fill in brand new
|
:c:func:`PyTuple_SET_ITEM`, this should only be used to fill in brand new
|
||||||
instances.
|
instances.
|
||||||
|
|
||||||
|
Bounds checking is performed as an assertion if Python is built in
|
||||||
|
:ref:`debug mode <debug-build>` or :option:`with assertions <--with-assertions>`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This function "steals" a reference to *o*.
|
This function "steals" a reference to *o*.
|
||||||
|
@ -215,9 +226,7 @@ type.
|
||||||
|
|
||||||
.. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o)
|
.. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o)
|
||||||
|
|
||||||
Similar to :c:func:`PyStructSequence_SetItem`, but implemented as a static
|
Alias to :c:func:`PyStructSequence_SetItem`.
|
||||||
inlined function.
|
|
||||||
|
|
||||||
.. note::
|
.. versionchanged:: 3.13
|
||||||
|
Now implemented as an alias to :c:func:`PyStructSequence_SetItem`.
|
||||||
This function "steals" a reference to *o*.
|
|
||||||
|
|
|
@ -441,6 +441,12 @@ New Features
|
||||||
``NULL`` if the referent is no longer live.
|
``NULL`` if the referent is no longer live.
|
||||||
(Contributed by Victor Stinner in :gh:`105927`.)
|
(Contributed by Victor Stinner in :gh:`105927`.)
|
||||||
|
|
||||||
|
* If Python is built in :ref:`debug mode <debug-build>` or :option:`with
|
||||||
|
assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and
|
||||||
|
:c:func:`PyList_SET_ITEM` now check the index argument with an assertion.
|
||||||
|
If the assertion fails, make sure that the size is set before.
|
||||||
|
(Contributed by Victor Stinner in :gh:`106168`.)
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ static inline Py_ssize_t PyList_GET_SIZE(PyObject *op) {
|
||||||
static inline void
|
static inline void
|
||||||
PyList_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
|
PyList_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
|
||||||
PyListObject *list = _PyList_CAST(op);
|
PyListObject *list = _PyList_CAST(op);
|
||||||
|
assert(0 <= index);
|
||||||
|
assert(index < Py_SIZE(list));
|
||||||
list->ob_item[index] = value;
|
list->ob_item[index] = value;
|
||||||
}
|
}
|
||||||
#define PyList_SET_ITEM(op, index, value) \
|
#define PyList_SET_ITEM(op, index, value) \
|
||||||
|
|
|
@ -31,6 +31,8 @@ static inline Py_ssize_t PyTuple_GET_SIZE(PyObject *op) {
|
||||||
static inline void
|
static inline void
|
||||||
PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
|
PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
|
||||||
PyTupleObject *tuple = _PyTuple_CAST(op);
|
PyTupleObject *tuple = _PyTuple_CAST(op);
|
||||||
|
assert(0 <= index);
|
||||||
|
assert(index < Py_SIZE(tuple));
|
||||||
tuple->ob_item[index] = value;
|
tuple->ob_item[index] = value;
|
||||||
}
|
}
|
||||||
#define PyTuple_SET_ITEM(op, index, value) \
|
#define PyTuple_SET_ITEM(op, index, value) \
|
||||||
|
|
|
@ -49,8 +49,8 @@ _PyList_AppendTakeRef(PyListObject *self, PyObject *newitem)
|
||||||
Py_ssize_t allocated = self->allocated;
|
Py_ssize_t allocated = self->allocated;
|
||||||
assert((size_t)len + 1 < PY_SSIZE_T_MAX);
|
assert((size_t)len + 1 < PY_SSIZE_T_MAX);
|
||||||
if (allocated > len) {
|
if (allocated > len) {
|
||||||
PyList_SET_ITEM(self, len, newitem);
|
|
||||||
Py_SET_SIZE(self, len + 1);
|
Py_SET_SIZE(self, len + 1);
|
||||||
|
PyList_SET_ITEM(self, len, newitem);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _PyList_AppendTakeRefListResize(self, newitem);
|
return _PyList_AppendTakeRefListResize(self, newitem);
|
||||||
|
|
|
@ -31,18 +31,15 @@ PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc);
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
|
PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
|
||||||
typedef PyTupleObject PyStructSequence;
|
|
||||||
|
|
||||||
/* Macro, *only* to be used to fill in brand new objects */
|
|
||||||
#define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM((op), (i), (v))
|
|
||||||
|
|
||||||
#define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM((op), (i))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*);
|
PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*);
|
||||||
PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t);
|
PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t);
|
||||||
|
|
||||||
|
#ifndef Py_LIMITED_API
|
||||||
|
typedef PyTupleObject PyStructSequence;
|
||||||
|
#define PyStructSequence_SET_ITEM PyStructSequence_SetItem
|
||||||
|
#define PyStructSequence_GET_ITEM PyStructSequence_GetItem
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
If Python is built in :ref:`debug mode <debug-build>` or :option:`with
|
||||||
|
assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and
|
||||||
|
:c:func:`PyList_SET_ITEM` now check the index argument with an assertion. If
|
||||||
|
the assertion fails, make sure that the size is set before. Patch by Victor
|
||||||
|
Stinner.
|
|
@ -953,8 +953,9 @@ list_extend(PyListObject *self, PyObject *iterable)
|
||||||
}
|
}
|
||||||
if (Py_SIZE(self) < self->allocated) {
|
if (Py_SIZE(self) < self->allocated) {
|
||||||
/* steals ref */
|
/* steals ref */
|
||||||
PyList_SET_ITEM(self, Py_SIZE(self), item);
|
Py_ssize_t len = Py_SIZE(self);
|
||||||
Py_SET_SIZE(self, Py_SIZE(self) + 1);
|
Py_SET_SIZE(self, len + 1);
|
||||||
|
PyList_SET_ITEM(self, len, item);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_PyList_AppendTakeRef(self, item) < 0)
|
if (_PyList_AppendTakeRef(self, item) < 0)
|
||||||
|
|
|
@ -74,15 +74,28 @@ PyStructSequence_New(PyTypeObject *type)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
|
PyStructSequence_SetItem(PyObject *op, Py_ssize_t index, PyObject *value)
|
||||||
{
|
{
|
||||||
PyStructSequence_SET_ITEM(op, i, v);
|
PyTupleObject *tuple = _PyTuple_CAST(op);
|
||||||
|
assert(0 <= index);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
Py_ssize_t n_fields = REAL_SIZE(op);
|
||||||
|
assert(n_fields >= 0);
|
||||||
|
assert(index < n_fields);
|
||||||
|
#endif
|
||||||
|
tuple->ob_item[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
|
PyStructSequence_GetItem(PyObject *op, Py_ssize_t index)
|
||||||
{
|
{
|
||||||
return PyStructSequence_GET_ITEM(op, i);
|
assert(0 <= index);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
Py_ssize_t n_fields = REAL_SIZE(op);
|
||||||
|
assert(n_fields >= 0);
|
||||||
|
assert(index < n_fields);
|
||||||
|
#endif
|
||||||
|
return PyTuple_GET_ITEM(op, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,7 +300,7 @@ structseq_repr(PyStructSequence *obj)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *value = PyStructSequence_GET_ITEM(obj, i);
|
PyObject *value = PyStructSequence_GetItem((PyObject*)obj, i);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
PyObject *repr = PyObject_Repr(value);
|
PyObject *repr = PyObject_Repr(value);
|
||||||
if (repr == NULL) {
|
if (repr == NULL) {
|
||||||
|
|
Loading…
Reference in New Issue