mirror of https://github.com/python/cpython
gh-121115: Skip __index__ in PyLong_AsNativeBytes by default (GH-121118)
This commit is contained in:
parent
81a654a342
commit
2894aa14f2
|
@ -405,14 +405,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
||||||
|
|
||||||
Passing zero to *n_bytes* will return the size of a buffer that would
|
Passing zero to *n_bytes* will return the size of a buffer that would
|
||||||
be large enough to hold the value. This may be larger than technically
|
be large enough to hold the value. This may be larger than technically
|
||||||
necessary, but not unreasonably so.
|
necessary, but not unreasonably so. If *n_bytes=0*, *buffer* may be
|
||||||
|
``NULL``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Passing *n_bytes=0* to this function is not an accurate way to determine
|
Passing *n_bytes=0* to this function is not an accurate way to determine
|
||||||
the bit length of a value.
|
the bit length of the value.
|
||||||
|
|
||||||
If *n_bytes=0*, *buffer* may be ``NULL``.
|
|
||||||
|
|
||||||
To get at the entire Python value of an unknown size, the function can be
|
To get at the entire Python value of an unknown size, the function can be
|
||||||
called twice: first to determine the buffer size, then to fill it::
|
called twice: first to determine the buffer size, then to fill it::
|
||||||
|
@ -462,6 +461,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
||||||
.. c:macro:: Py_ASNATIVEBYTES_NATIVE_ENDIAN ``3``
|
.. c:macro:: Py_ASNATIVEBYTES_NATIVE_ENDIAN ``3``
|
||||||
.. c:macro:: Py_ASNATIVEBYTES_UNSIGNED_BUFFER ``4``
|
.. c:macro:: Py_ASNATIVEBYTES_UNSIGNED_BUFFER ``4``
|
||||||
.. c:macro:: Py_ASNATIVEBYTES_REJECT_NEGATIVE ``8``
|
.. c:macro:: Py_ASNATIVEBYTES_REJECT_NEGATIVE ``8``
|
||||||
|
.. c:macro:: Py_ASNATIVEBYTES_ALLOW_INDEX ``16``
|
||||||
============================================= ======
|
============================================= ======
|
||||||
|
|
||||||
Specifying ``Py_ASNATIVEBYTES_NATIVE_ENDIAN`` will override any other endian
|
Specifying ``Py_ASNATIVEBYTES_NATIVE_ENDIAN`` will override any other endian
|
||||||
|
@ -483,6 +483,13 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
||||||
provided there is enough space for at least one sign bit, regardless of
|
provided there is enough space for at least one sign bit, regardless of
|
||||||
whether ``Py_ASNATIVEBYTES_UNSIGNED_BUFFER`` was specified.
|
whether ``Py_ASNATIVEBYTES_UNSIGNED_BUFFER`` was specified.
|
||||||
|
|
||||||
|
If ``Py_ASNATIVEBYTES_ALLOW_INDEX`` is specified and a non-integer value is
|
||||||
|
passed, its :meth:`~object.__index__` method will be called first. This may
|
||||||
|
result in Python code executing and other threads being allowed to run, which
|
||||||
|
could cause changes to other objects or values in use. When *flags* is
|
||||||
|
``-1``, this option is not set, and non-integer values will raise
|
||||||
|
:exc:`TypeError`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
With the default *flags* (``-1``, or *UNSIGNED_BUFFER* without
|
With the default *flags* (``-1``, or *UNSIGNED_BUFFER* without
|
||||||
|
|
|
@ -10,6 +10,7 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base);
|
||||||
#define Py_ASNATIVEBYTES_NATIVE_ENDIAN 3
|
#define Py_ASNATIVEBYTES_NATIVE_ENDIAN 3
|
||||||
#define Py_ASNATIVEBYTES_UNSIGNED_BUFFER 4
|
#define Py_ASNATIVEBYTES_UNSIGNED_BUFFER 4
|
||||||
#define Py_ASNATIVEBYTES_REJECT_NEGATIVE 8
|
#define Py_ASNATIVEBYTES_REJECT_NEGATIVE 8
|
||||||
|
#define Py_ASNATIVEBYTES_ALLOW_INDEX 16
|
||||||
|
|
||||||
/* PyLong_AsNativeBytes: Copy the integer value to a native variable.
|
/* PyLong_AsNativeBytes: Copy the integer value to a native variable.
|
||||||
buffer points to the first byte of the variable.
|
buffer points to the first byte of the variable.
|
||||||
|
@ -20,8 +21,10 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base);
|
||||||
* 2 - native endian
|
* 2 - native endian
|
||||||
* 4 - unsigned destination (e.g. don't reject copying 255 into one byte)
|
* 4 - unsigned destination (e.g. don't reject copying 255 into one byte)
|
||||||
* 8 - raise an exception for negative inputs
|
* 8 - raise an exception for negative inputs
|
||||||
If flags is -1 (all bits set), native endian is used and value truncation
|
* 16 - call __index__ on non-int types
|
||||||
behaves most like C (allows negative inputs and allow MSB set).
|
If flags is -1 (all bits set), native endian is used, value truncation
|
||||||
|
behaves most like C (allows negative inputs and allow MSB set), and non-int
|
||||||
|
objects will raise a TypeError.
|
||||||
Big endian mode will write the most significant byte into the address
|
Big endian mode will write the most significant byte into the address
|
||||||
directly referenced by buffer; little endian will write the least significant
|
directly referenced by buffer; little endian will write the least significant
|
||||||
byte into that address.
|
byte into that address.
|
||||||
|
|
|
@ -496,8 +496,9 @@ class LongTests(unittest.TestCase):
|
||||||
"PyLong_AsNativeBytes(v, <unknown>, 0, -1)")
|
"PyLong_AsNativeBytes(v, <unknown>, 0, -1)")
|
||||||
self.assertEqual(buffer, b"\x5a",
|
self.assertEqual(buffer, b"\x5a",
|
||||||
"buffer overwritten when it should not have been")
|
"buffer overwritten when it should not have been")
|
||||||
# Also check via the __index__ path
|
# Also check via the __index__ path.
|
||||||
self.assertEqual(expect, asnativebytes(Index(v), buffer, 0, -1),
|
# We pass Py_ASNATIVEBYTES_NATIVE_ENDIAN | ALLOW_INDEX
|
||||||
|
self.assertEqual(expect, asnativebytes(Index(v), buffer, 0, 3 | 16),
|
||||||
"PyLong_AsNativeBytes(Index(v), <unknown>, 0, -1)")
|
"PyLong_AsNativeBytes(Index(v), <unknown>, 0, -1)")
|
||||||
self.assertEqual(buffer, b"\x5a",
|
self.assertEqual(buffer, b"\x5a",
|
||||||
"buffer overwritten when it should not have been")
|
"buffer overwritten when it should not have been")
|
||||||
|
@ -607,6 +608,12 @@ class LongTests(unittest.TestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
asnativebytes(-1, buffer, 0, 8)
|
asnativebytes(-1, buffer, 0, 8)
|
||||||
|
|
||||||
|
# Ensure omitting Py_ASNATIVEBYTES_ALLOW_INDEX raises on __index__ value
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
asnativebytes(Index(1), buffer, 0, -1)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
asnativebytes(Index(1), buffer, 0, 3)
|
||||||
|
|
||||||
# Check a few error conditions. These are validated in code, but are
|
# Check a few error conditions. These are validated in code, but are
|
||||||
# unspecified in docs, so if we make changes to the implementation, it's
|
# unspecified in docs, so if we make changes to the implementation, it's
|
||||||
# fine to just update these tests rather than preserve the behaviour.
|
# fine to just update these tests rather than preserve the behaviour.
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
:c:func:`PyLong_AsNativeBytes` no longer uses :meth:`~object.__index__`
|
||||||
|
methods by default. The ``Py_ASNATIVEBYTES_ALLOW_INDEX`` flag has been added
|
||||||
|
to allow it.
|
|
@ -1128,13 +1128,17 @@ PyLong_AsNativeBytes(PyObject* vv, void* buffer, Py_ssize_t n, int flags)
|
||||||
if (PyLong_Check(vv)) {
|
if (PyLong_Check(vv)) {
|
||||||
v = (PyLongObject *)vv;
|
v = (PyLongObject *)vv;
|
||||||
}
|
}
|
||||||
else {
|
else if (flags != -1 && (flags & Py_ASNATIVEBYTES_ALLOW_INDEX)) {
|
||||||
v = (PyLongObject *)_PyNumber_Index(vv);
|
v = (PyLongObject *)_PyNumber_Index(vv);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
do_decref = 1;
|
do_decref = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expect int, got %T", vv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags != -1 && (flags & Py_ASNATIVEBYTES_REJECT_NEGATIVE))
|
if ((flags != -1 && (flags & Py_ASNATIVEBYTES_REJECT_NEGATIVE))
|
||||||
&& _PyLong_IsNegative(v)) {
|
&& _PyLong_IsNegative(v)) {
|
||||||
|
|
Loading…
Reference in New Issue