Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d8346d6

Browse filesBrowse files
[3.12] gh-115011: Improve support of __index__() in setters of members with unsigned integer type (GH-115029) (GH-115294)
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. (cherry picked from commit d9d6909)
1 parent d65cd8b commit d8346d6
Copy full SHA for d8346d6

File tree

Expand file treeCollapse file tree

3 files changed

+62
-67
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+62
-67
lines changed

‎Lib/test/test_capi/test_structmembers.py

Copy file name to clipboardExpand all lines: Lib/test/test_capi/test_structmembers.py
+14-30Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -81,36 +81,22 @@ def _test_int_range(self, name, minval, maxval, *, hardlimit=None,
8181
self._test_warn(name, maxval+1, minval)
8282
self._test_warn(name, hardmaxval)
8383

84-
if indexlimit is None:
85-
indexlimit = hardlimit
86-
if not indexlimit:
84+
if indexlimit is False:
8785
self.assertRaises(TypeError, setattr, ts, name, Index(minval))
8886
self.assertRaises(TypeError, setattr, ts, name, Index(maxval))
8987
else:
90-
hardminindexval, hardmaxindexval = indexlimit
9188
self._test_write(name, Index(minval), minval)
92-
if minval < hardminindexval:
93-
self._test_write(name, Index(hardminindexval), hardminindexval)
94-
if maxval < hardmaxindexval:
95-
self._test_write(name, Index(maxval), maxval)
96-
else:
97-
self._test_write(name, Index(hardmaxindexval), hardmaxindexval)
98-
self._test_overflow(name, Index(hardminindexval-1))
99-
if name in ('T_UINT', 'T_ULONG'):
100-
self.assertRaises(TypeError, setattr, self.ts, name,
101-
Index(hardmaxindexval+1))
102-
self.assertRaises(TypeError, setattr, self.ts, name,
103-
Index(2**1000))
104-
else:
105-
self._test_overflow(name, Index(hardmaxindexval+1))
106-
self._test_overflow(name, Index(2**1000))
89+
self._test_write(name, Index(maxval), maxval)
90+
self._test_overflow(name, Index(hardminval-1))
91+
self._test_overflow(name, Index(hardmaxval+1))
92+
self._test_overflow(name, Index(2**1000))
10793
self._test_overflow(name, Index(-2**1000))
108-
if hardminindexval < minval and name != 'T_ULONGLONG':
109-
self._test_warn(name, Index(hardminindexval))
110-
self._test_warn(name, Index(minval-1))
111-
if maxval < hardmaxindexval:
112-
self._test_warn(name, Index(maxval+1))
113-
self._test_warn(name, Index(hardmaxindexval))
94+
if hardminval < minval:
95+
self._test_warn(name, Index(hardminval))
96+
self._test_warn(name, Index(minval-1), maxval)
97+
if maxval < hardmaxval:
98+
self._test_warn(name, Index(maxval+1), minval)
99+
self._test_warn(name, Index(hardmaxval))
114100

115101
def test_bool(self):
116102
ts = self.ts
@@ -138,22 +124,20 @@ def test_int(self):
138124
self._test_int_range('T_INT', INT_MIN, INT_MAX,
139125
hardlimit=(LONG_MIN, LONG_MAX))
140126
self._test_int_range('T_UINT', 0, UINT_MAX,
141-
hardlimit=(LONG_MIN, ULONG_MAX),
142-
indexlimit=(LONG_MIN, LONG_MAX))
127+
hardlimit=(LONG_MIN, ULONG_MAX))
143128

144129
def test_long(self):
145130
self._test_int_range('T_LONG', LONG_MIN, LONG_MAX)
146131
self._test_int_range('T_ULONG', 0, ULONG_MAX,
147-
hardlimit=(LONG_MIN, ULONG_MAX),
148-
indexlimit=(LONG_MIN, LONG_MAX))
132+
hardlimit=(LONG_MIN, ULONG_MAX))
149133

150134
def test_py_ssize_t(self):
151135
self._test_int_range('T_PYSSIZET', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, indexlimit=False)
152136

153137
def test_longlong(self):
154138
self._test_int_range('T_LONGLONG', LLONG_MIN, LLONG_MAX)
155139
self._test_int_range('T_ULONGLONG', 0, ULLONG_MAX,
156-
indexlimit=(LONG_MIN, LONG_MAX))
140+
hardlimit=(LONG_MIN, ULLONG_MAX))
157141

158142
def test_bad_assignments(self):
159143
ts = self.ts
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Setters for members with an unsigned integer type now support the same range
2+
of valid values for objects that has a :meth:`~object.__index__` method as
3+
for :class:`int`.

‎Python/structmember.c

Copy file name to clipboardExpand all lines: Python/structmember.c
+45-37Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include "Python.h"
55
#include "structmember.h" // PyMemberDef
6+
#include "pycore_abstract.h" // _PyNumber_Index()
7+
#include "pycore_long.h" // _PyLong_IsNegative()
8+
69

710
PyObject *
811
PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
@@ -200,27 +203,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
200203
case T_UINT: {
201204
/* XXX: For compatibility, accept negative int values
202205
as well. */
203-
int overflow;
204-
long long_val = PyLong_AsLongAndOverflow(v, &overflow);
205-
if (long_val == -1 && PyErr_Occurred()) {
206-
return -1;
207-
}
208-
if (overflow < 0) {
209-
PyErr_SetString(PyExc_OverflowError,
210-
"Python int too large to convert to C long");
206+
v = _PyNumber_Index(v);
207+
if (v == NULL) {
211208
return -1;
212209
}
213-
else if (!overflow) {
214-
*(unsigned int *)addr = (unsigned int)(unsigned long)long_val;
215-
if (long_val < 0) {
216-
WARN("Writing negative value into unsigned field");
217-
}
218-
else if ((unsigned long)long_val > UINT_MAX) {
219-
WARN("Truncation of value to unsigned short");
210+
if (_PyLong_IsNegative((PyLongObject *)v)) {
211+
long long_val = PyLong_AsLong(v);
212+
Py_DECREF(v);
213+
if (long_val == -1 && PyErr_Occurred()) {
214+
return -1;
220215
}
216+
*(unsigned int *)addr = (unsigned int)(unsigned long)long_val;
217+
WARN("Writing negative value into unsigned field");
221218
}
222219
else {
223220
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
221+
Py_DECREF(v);
224222
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
225223
return -1;
226224
}
@@ -240,24 +238,22 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
240238
case T_ULONG: {
241239
/* XXX: For compatibility, accept negative int values
242240
as well. */
243-
int overflow;
244-
long long_val = PyLong_AsLongAndOverflow(v, &overflow);
245-
if (long_val == -1 && PyErr_Occurred()) {
246-
return -1;
247-
}
248-
if (overflow < 0) {
249-
PyErr_SetString(PyExc_OverflowError,
250-
"Python int too large to convert to C long");
241+
v = _PyNumber_Index(v);
242+
if (v == NULL) {
251243
return -1;
252244
}
253-
else if (!overflow) {
254-
*(unsigned long *)addr = (unsigned long)long_val;
255-
if (long_val < 0) {
256-
WARN("Writing negative value into unsigned field");
245+
if (_PyLong_IsNegative((PyLongObject *)v)) {
246+
long long_val = PyLong_AsLong(v);
247+
Py_DECREF(v);
248+
if (long_val == -1 && PyErr_Occurred()) {
249+
return -1;
257250
}
251+
*(unsigned long *)addr = (unsigned long)long_val;
252+
WARN("Writing negative value into unsigned field");
258253
}
259254
else {
260255
unsigned long ulong_val = PyLong_AsUnsignedLong(v);
256+
Py_DECREF(v);
261257
if (ulong_val == (unsigned long)-1 && PyErr_Occurred()) {
262258
return -1;
263259
}
@@ -313,18 +309,30 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
313309
return -1;
314310
break;
315311
}
316-
case T_ULONGLONG:{
317-
unsigned long long value;
318-
/* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
319-
doesn't ??? */
320-
if (PyLong_Check(v))
321-
*(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
322-
else
323-
*(unsigned long long*)addr = value = PyLong_AsLong(v);
324-
if ((value == (unsigned long long)-1) && PyErr_Occurred())
312+
case Py_T_ULONGLONG: {
313+
v = _PyNumber_Index(v);
314+
if (v == NULL) {
325315
return -1;
326-
break;
327316
}
317+
if (_PyLong_IsNegative((PyLongObject *)v)) {
318+
long long_val = PyLong_AsLong(v);
319+
Py_DECREF(v);
320+
if (long_val == -1 && PyErr_Occurred()) {
321+
return -1;
322+
}
323+
*(unsigned long long *)addr = (unsigned long long)(long long)long_val;
324+
WARN("Writing negative value into unsigned field");
325+
}
326+
else {
327+
unsigned long long ulonglong_val = PyLong_AsUnsignedLongLong(v);
328+
Py_DECREF(v);
329+
if (ulonglong_val == (unsigned long long)-1 && PyErr_Occurred()) {
330+
return -1;
331+
}
332+
*(unsigned long long*)addr = ulonglong_val;
333+
}
334+
break;
335+
}
328336
default:
329337
PyErr_Format(PyExc_SystemError,
330338
"bad memberdescr type for %s", l->name);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.