diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2024-02-11 10:45:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-11 10:45:58 (GMT) |
commit | d9d6909697501a2604d5895f9f88aeec61274ab0 (patch) | |
tree | cdc8dbb18978002fa06eb6565be16d045ec6c7e5 /Python | |
parent | d2c4baa41ff93cd5695c201d40e20a88458ecc26 (diff) | |
download | cpython-d9d6909697501a2604d5895f9f88aeec61274ab0.zip cpython-d9d6909697501a2604d5895f9f88aeec61274ab0.tar.gz cpython-d9d6909697501a2604d5895f9f88aeec61274ab0.tar.bz2 |
gh-115011: Improve support of __index__() in setters of members with unsigned integer type (GH-115029)
Setters for members with an unsigned integer type now support
the same range of valid values for objects that has a __index__()
method as for int.
Previously, Py_T_UINT, Py_T_ULONG and Py_T_ULLONG did not support
objects that has a __index__() method larger than LONG_MAX.
Py_T_ULLONG did not support negative ints. Now it supports them and
emits a RuntimeWarning.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/structmember.c | 81 |
1 files changed, 44 insertions, 37 deletions
diff --git a/Python/structmember.c b/Python/structmember.c index c9f03a4..ba881d1 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -2,6 +2,8 @@ /* Map C struct members to Python object attributes */ #include "Python.h" +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_long.h" // _PyLong_IsNegative() PyObject * @@ -200,27 +202,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) case Py_T_UINT: { /* XXX: For compatibility, accept negative int values as well. */ - int overflow; - long long_val = PyLong_AsLongAndOverflow(v, &overflow); - if (long_val == -1 && PyErr_Occurred()) { - return -1; - } - if (overflow < 0) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C long"); + v = _PyNumber_Index(v); + if (v == NULL) { return -1; } - else if (!overflow) { - *(unsigned int *)addr = (unsigned int)(unsigned long)long_val; - if (long_val < 0) { - WARN("Writing negative value into unsigned field"); - } - else if ((unsigned long)long_val > UINT_MAX) { - WARN("Truncation of value to unsigned short"); + if (_PyLong_IsNegative((PyLongObject *)v)) { + long long_val = PyLong_AsLong(v); + Py_DECREF(v); + if (long_val == -1 && PyErr_Occurred()) { + return -1; } + *(unsigned int *)addr = (unsigned int)(unsigned long)long_val; + WARN("Writing negative value into unsigned field"); } else { unsigned long ulong_val = PyLong_AsUnsignedLong(v); + Py_DECREF(v); if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) { return -1; } @@ -240,24 +237,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) case Py_T_ULONG: { /* XXX: For compatibility, accept negative int values as well. */ - int overflow; - long long_val = PyLong_AsLongAndOverflow(v, &overflow); - if (long_val == -1 && PyErr_Occurred()) { - return -1; - } - if (overflow < 0) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C long"); + v = _PyNumber_Index(v); + if (v == NULL) { return -1; } - else if (!overflow) { - *(unsigned long *)addr = (unsigned long)long_val; - if (long_val < 0) { - WARN("Writing negative value into unsigned field"); + if (_PyLong_IsNegative((PyLongObject *)v)) { + long long_val = PyLong_AsLong(v); + Py_DECREF(v); + if (long_val == -1 && PyErr_Occurred()) { + return -1; } + *(unsigned long *)addr = (unsigned long)long_val; + WARN("Writing negative value into unsigned field"); } else { unsigned long ulong_val = PyLong_AsUnsignedLong(v); + Py_DECREF(v); if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) { return -1; } @@ -313,18 +308,30 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) return -1; break; } - case Py_T_ULONGLONG:{ - unsigned long long value; - /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong - doesn't ??? */ - if (PyLong_Check(v)) - *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v); - else - *(unsigned long long*)addr = value = PyLong_AsLong(v); - if ((value == (unsigned long long)-1) && PyErr_Occurred()) + case Py_T_ULONGLONG: { + v = _PyNumber_Index(v); + if (v == NULL) { return -1; - break; } + if (_PyLong_IsNegative((PyLongObject *)v)) { + long long_val = PyLong_AsLong(v); + Py_DECREF(v); + if (long_val == -1 && PyErr_Occurred()) { + return -1; + } + *(unsigned long long *)addr = (unsigned long long)(long long)long_val; + WARN("Writing negative value into unsigned field"); + } + else { + unsigned long long ulonglong_val = PyLong_AsUnsignedLongLong(v); + Py_DECREF(v); + if (ulonglong_val == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + *(unsigned long long*)addr = ulonglong_val; + } + break; + } default: PyErr_Format(PyExc_SystemError, "bad memberdescr type for %s", l->name); |