mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-114388: Fix warnings when assign an unsigned integer member (GH-114391)
* Fix a RuntimeWarning emitted when assign an integer-like value that is not an instance of int to an attribute that corresponds to a C struct member of type T_UINT and T_ULONG. * Fix a double RuntimeWarning emitted when assign a negative integer value to an attribute that corresponds to a C struct member of type T_UINT.
This commit is contained in:
parent
0ea366240b
commit
3ddc515255
3 changed files with 98 additions and 29 deletions
|
@ -14,6 +14,13 @@ from _testcapi import (_test_structmembersType_OldAPI,
|
|||
PY_SSIZE_T_MAX, PY_SSIZE_T_MIN,
|
||||
)
|
||||
|
||||
|
||||
class Index:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __index__(self):
|
||||
return self.value
|
||||
|
||||
# There are two classes: one using <structmember.h> and another using
|
||||
# `Py_`-prefixed API. They should behave the same in Python
|
||||
|
||||
|
@ -72,6 +79,10 @@ class ReadWriteTests:
|
|||
self.assertEqual(ts.T_INT, INT_MIN)
|
||||
ts.T_UINT = UINT_MAX
|
||||
self.assertEqual(ts.T_UINT, UINT_MAX)
|
||||
ts.T_UINT = Index(0)
|
||||
self.assertEqual(ts.T_UINT, 0)
|
||||
ts.T_UINT = Index(INT_MAX)
|
||||
self.assertEqual(ts.T_UINT, INT_MAX)
|
||||
|
||||
def test_long(self):
|
||||
ts = self.ts
|
||||
|
@ -81,6 +92,10 @@ class ReadWriteTests:
|
|||
self.assertEqual(ts.T_LONG, LONG_MIN)
|
||||
ts.T_ULONG = ULONG_MAX
|
||||
self.assertEqual(ts.T_ULONG, ULONG_MAX)
|
||||
ts.T_ULONG = Index(0)
|
||||
self.assertEqual(ts.T_ULONG, 0)
|
||||
ts.T_ULONG = Index(LONG_MAX)
|
||||
self.assertEqual(ts.T_ULONG, LONG_MAX)
|
||||
|
||||
def test_py_ssize_t(self):
|
||||
ts = self.ts
|
||||
|
@ -173,6 +188,28 @@ class TestWarnings:
|
|||
with warnings_helper.check_warnings(('', RuntimeWarning)):
|
||||
ts.T_USHORT = USHRT_MAX+1
|
||||
|
||||
def test_int(self):
|
||||
ts = self.ts
|
||||
if LONG_MIN < INT_MIN:
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
ts.T_INT = INT_MIN-1
|
||||
if LONG_MAX > INT_MAX:
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
ts.T_INT = INT_MAX+1
|
||||
|
||||
def test_uint(self):
|
||||
ts = self.ts
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
ts.T_UINT = -1
|
||||
if ULONG_MAX > UINT_MAX:
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
ts.T_UINT = UINT_MAX+1
|
||||
|
||||
def test_ulong(self):
|
||||
ts = self.ts
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
ts.T_ULONG = -1
|
||||
|
||||
class TestWarnings_OldAPI(TestWarnings, unittest.TestCase):
|
||||
cls = _test_structmembersType_OldAPI
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Fix a :exc:`RuntimeWarning` emitted when assign an integer-like value that
|
||||
is not an instance of :class:`int` to an attribute that corresponds to a C
|
||||
struct member of :ref:`type <PyMemberDef-types>` T_UINT and T_ULONG. Fix a
|
||||
double :exc:`RuntimeWarning` emitted when assign a negative integer value to
|
||||
an attribute that corresponds to a C struct member of type T_UINT.
|
|
@ -197,45 +197,72 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
|
|||
WARN("Truncation of value to int");
|
||||
break;
|
||||
}
|
||||
case Py_T_UINT:{
|
||||
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
|
||||
if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
|
||||
/* XXX: For compatibility, accept negative int values
|
||||
as well. */
|
||||
PyErr_Clear();
|
||||
ulong_val = PyLong_AsLong(v);
|
||||
if ((ulong_val == (unsigned long)-1) &&
|
||||
PyErr_Occurred())
|
||||
return -1;
|
||||
*(unsigned int *)addr = (unsigned int)ulong_val;
|
||||
WARN("Writing negative value into unsigned field");
|
||||
} else
|
||||
*(unsigned int *)addr = (unsigned int)ulong_val;
|
||||
if (ulong_val > UINT_MAX)
|
||||
WARN("Truncation of value to unsigned int");
|
||||
break;
|
||||
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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
|
||||
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
*(unsigned int*)addr = (unsigned int)ulong_val;
|
||||
if (ulong_val > UINT_MAX) {
|
||||
WARN("Truncation of value to unsigned int");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Py_T_LONG:{
|
||||
*(long*)addr = PyLong_AsLong(v);
|
||||
if ((*(long*)addr == -1) && PyErr_Occurred())
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
case Py_T_ULONG:{
|
||||
*(unsigned long*)addr = PyLong_AsUnsignedLong(v);
|
||||
if ((*(unsigned long*)addr == (unsigned long)-1)
|
||||
&& PyErr_Occurred()) {
|
||||
/* XXX: For compatibility, accept negative int values
|
||||
as well. */
|
||||
PyErr_Clear();
|
||||
*(unsigned long*)addr = PyLong_AsLong(v);
|
||||
if ((*(unsigned long*)addr == (unsigned long)-1)
|
||||
&& PyErr_Occurred())
|
||||
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");
|
||||
}
|
||||
else if (!overflow) {
|
||||
*(unsigned long *)addr = (unsigned long)long_val;
|
||||
if (long_val < 0) {
|
||||
WARN("Writing negative value into unsigned field");
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
|
||||
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
WARN("Writing negative value into unsigned field");
|
||||
}
|
||||
*(unsigned long*)addr = ulong_val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case Py_T_PYSSIZET:{
|
||||
*(Py_ssize_t*)addr = PyLong_AsSsize_t(v);
|
||||
if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue