From cb701f504e9a174bbc42ade4ae1195509e23670a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 9 Jul 2024 15:46:38 +0200 Subject: [PATCH 01/11] gh-121153: Change _PyLong_CompactValue() return type to int --- Include/cpython/longintrepr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index d841c043f37fc4..e742bef15c0431 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -126,14 +126,14 @@ _PyLong_IsCompact(PyLongObject* op) { #define PyUnstable_Long_IsCompact _PyLong_IsCompact -static inline Py_ssize_t +static inline int _PyLong_CompactValue(PyLongObject *op) { Py_ssize_t sign; assert(PyType_HasFeature(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); - return sign * (Py_ssize_t)op->long_value.ob_digit[0]; + return sign * (int)op->long_value.ob_digit[0]; } #define PyUnstable_Long_CompactValue _PyLong_CompactValue From b9fb88e5b9128f60602ff206e3eb77b460831543 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jul 2024 15:40:52 +0200 Subject: [PATCH 02/11] Update usage --- Objects/listobject.c | 5 ++--- Objects/longobject.c | 18 +++++------------- Python/bltinmodule.c | 5 ++--- Python/bytecodes.c | 4 ++-- Python/executor_cases.c.h | 4 ++-- Python/generated_cases.c.h | 4 ++-- 6 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index f29f58dc25be04..adc085a0d4e211 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2751,7 +2751,6 @@ static int unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) { PyLongObject *vl, *wl; - intptr_t v0, w0; int res; /* Modified from Objects/longobject.c:long_compare, assuming: */ @@ -2763,8 +2762,8 @@ unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) vl = (PyLongObject*)v; wl = (PyLongObject*)w; - v0 = _PyLong_CompactValue(vl); - w0 = _PyLong_CompactValue(wl); + int v0 = _PyLong_CompactValue(vl); + int w0 = _PyLong_CompactValue(wl); res = v0 < w0; assert(res == PyObject_RichCompareBool(v, w, Py_LT)); diff --git a/Objects/longobject.c b/Objects/longobject.c index 4ca259fb08e8c7..2bf922db0bde68 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -483,15 +483,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) do_decref = 1; } if (_PyLong_IsCompact(v)) { -#if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_CompactValue(v); - res = (long)tmp; - if (res != tmp) { - *overflow = tmp < 0 ? -1 : 1; - } -#else res = _PyLong_CompactValue(v); -#endif } else { res = -1; @@ -632,8 +624,8 @@ PyLong_AsUnsignedLong(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { -#if SIZEOF_LONG < SIZEOF_VOID_P - intptr_t tmp = _PyLong_CompactValue(v); +#if SIZEOF_INT < SIZEOF_VOID_P + int tmp = _PyLong_CompactValue(v); unsigned long res = (unsigned long)tmp; if (res != tmp) { goto overflow; @@ -1109,8 +1101,8 @@ PyLong_AsNativeBytes(PyObject* vv, void* buffer, Py_ssize_t n, int flags) { PyLongObject *v; union { - Py_ssize_t v; - unsigned char b[sizeof(Py_ssize_t)]; + int v; + unsigned char b[sizeof(int)]; } cv; int do_decref = 0; Py_ssize_t res = 0; @@ -3579,7 +3571,7 @@ long_hash(PyLongObject *v) int sign; if (_PyLong_IsCompact(v)) { - x = _PyLong_CompactValue(v); + x = (Py_uhash_t)_PyLong_CompactValue(v); if (x == (Py_uhash_t)-1) { x = (Py_uhash_t)-2; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index a5b45e358d9efb..8b36a8e90b68ff 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2634,7 +2634,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) return PyLong_FromSsize_t(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { - Py_ssize_t b; + long b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ if (_PyLong_IsCompact((PyLongObject *)item)) { @@ -2644,8 +2644,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && - (i_result >= 0 ? (b <= LONG_MAX - i_result) - : (b >= LONG_MIN - i_result))) + (i_result >= 0 ? (1 - i_result) : (1 - i_result))) { i_result += b; Py_DECREF(item); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 84241c64ffae88..8bed70d6e3519b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2482,8 +2482,8 @@ dummy_func( STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && _PyLong_DigitCount((PyLongObject *)right_o) <= 1); - Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); - Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); + int ileft = _PyLong_CompactValue((PyLongObject *)left_o); + int iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 8f6bc75b528d9b..fe7bcda37619d1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2657,8 +2657,8 @@ STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && _PyLong_DigitCount((PyLongObject *)right_o) <= 1); - Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); - Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); + int ileft = _PyLong_CompactValue((PyLongObject *)left_o); + int iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 61057221291c0a..669add4ed8e2db 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2527,8 +2527,8 @@ STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && _PyLong_DigitCount((PyLongObject *)right_o) <= 1); - Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left_o); - Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right_o); + int ileft = _PyLong_CompactValue((PyLongObject *)left_o); + int iright = _PyLong_CompactValue((PyLongObject *)right_o); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left_o, (destructor)PyObject_Free); From eddd5fb17970012f47bd5c32ad69b4f6fc2301db Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jul 2024 15:41:23 +0200 Subject: [PATCH 03/11] Change sign type --- Include/cpython/longintrepr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index e742bef15c0431..579da525a67503 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -129,7 +129,7 @@ _PyLong_IsCompact(PyLongObject* op) { static inline int _PyLong_CompactValue(PyLongObject *op) { - Py_ssize_t sign; + int sign; assert(PyType_HasFeature(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); From c990b661cf7d9c191e4a589ae648e0332eef4a74 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jul 2024 15:45:39 +0200 Subject: [PATCH 04/11] Update PyLong_AsUnsignedLong() --- Objects/longobject.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 2bf922db0bde68..e0748ca667b4f5 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -624,15 +624,7 @@ PyLong_AsUnsignedLong(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { -#if SIZEOF_INT < SIZEOF_VOID_P - int tmp = _PyLong_CompactValue(v); - unsigned long res = (unsigned long)tmp; - if (res != tmp) { - goto overflow; - } -#else - return _PyLong_CompactValue(v); -#endif + return (unsigned long)(long)_PyLong_CompactValue(v); } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, From 58494f75487d961e73269d32497370880a320773 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 11 Jul 2024 13:55:31 +0200 Subject: [PATCH 05/11] Address Serhiy's review --- Objects/longobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index e0748ca667b4f5..dc5b4ee153d9c6 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3563,7 +3563,7 @@ long_hash(PyLongObject *v) int sign; if (_PyLong_IsCompact(v)) { - x = (Py_uhash_t)_PyLong_CompactValue(v); + x = (Py_uhash_t)(Py_hash_t)_PyLong_CompactValue(v); if (x == (Py_uhash_t)-1) { x = (Py_uhash_t)-2; } From 3b94066ef4f61b330375a83dcbf04eeaa228da53 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 11 Jul 2024 21:56:00 +0300 Subject: [PATCH 06/11] Add explicit conversions to unsigned types. --- Objects/longobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index dc5b4ee153d9c6..1bb3a96c1a6b38 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -669,7 +669,7 @@ PyLong_AsSize_t(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { - return _PyLong_CompactValue(v); + return (size_t)(Py_ssize_t)_PyLong_CompactValue(v); } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, @@ -706,7 +706,7 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long)_PyLong_CompactValue(v); + return (unsigned long)(long)_PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); int sign = _PyLong_NonCompactSign(v); @@ -1524,7 +1524,7 @@ PyLong_AsUnsignedLongLong(PyObject *vv) v = (PyLongObject*)vv; if (_PyLong_IsNonNegativeCompact(v)) { res = 0; - bytes = _PyLong_CompactValue(v); + bytes = (unsigned long long)(long long)_PyLong_CompactValue(v); } else { res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, @@ -1555,7 +1555,7 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long long)(signed long long)_PyLong_CompactValue(v); + return (unsigned long long)(long long)_PyLong_CompactValue(v); } i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); From 081df02108d6b4a5f3a1527c37d9a1f6ce1c37db Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 11 Jul 2024 22:17:51 +0300 Subject: [PATCH 07/11] Fix overflow check in sum(). --- Python/bltinmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 8b36a8e90b68ff..24f26b5968e10e 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2644,7 +2644,9 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && - (i_result >= 0 ? (1 - i_result) : (1 - i_result))) + /* PY_SSIZE_T_MIN <= i_result + b <= PY_SSIZE_T_MAX */ + (i_result >= 0 ? (b <= PY_SSIZE_T_MAX - i_result) + : (b >= PY_SSIZE_T_MIN - i_result))) { i_result += b; Py_DECREF(item); From 7360f85a671778f83a83c0b7dd30ce6cbc76c237 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 12 Jul 2024 14:03:28 +0300 Subject: [PATCH 08/11] Change also PyUnstable_Long_CompactValue(). --- Doc/c-api/long.rst | 2 +- Include/cpython/longobject.h | 2 +- Modules/_testcapi/long.c | 4 ++-- Objects/longobject.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 42162914c0aec8..93142e497d8c28 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -529,7 +529,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Exactly what values are considered compact is an implementation detail and is subject to change. -.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) +.. c:function:: int PyUnstable_Long_CompactValue(const PyLongObject* op) If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, return its value. diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index e7e0c3d9764f20..861b7313a27d7b 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -56,7 +56,7 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnsignedNativeBytes(const void* buffer, size_t n_bytes, int flags); PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op); -PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op); +PyAPI_FUNC(int) PyUnstable_Long_CompactValue(const PyLongObject* op); /* PyLong_GetSign. Get the sign of an integer object: 0, -1 or +1 for zero, negative or positive integer, respectively. diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 2b5e85d5707522..5dddf989d3c170 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -25,11 +25,11 @@ _testcapi_call_long_compact_api(PyObject *module, PyObject *arg) { assert(PyLong_Check(arg)); int is_compact = PyUnstable_Long_IsCompact((PyLongObject*)arg); - Py_ssize_t value = -1; + int value = -1; if (is_compact) { value = PyUnstable_Long_CompactValue((PyLongObject*)arg); } - return Py_BuildValue("in", is_compact, value); + return Py_BuildValue("ii", is_compact, value); } diff --git a/Objects/longobject.c b/Objects/longobject.c index 1bb3a96c1a6b38..2425659af5370c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6665,7 +6665,7 @@ PyUnstable_Long_IsCompact(const PyLongObject* op) { #undef PyUnstable_Long_CompactValue -Py_ssize_t +int PyUnstable_Long_CompactValue(const PyLongObject* op) { return _PyLong_CompactValue((PyLongObject*)op); } From deccdb16845c6efd551ba6762c94fed4447462c1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 12 Jul 2024 13:24:55 +0200 Subject: [PATCH 09/11] Update PyUnstable_Long_CompactValue() doc --- Doc/c-api/long.rst | 4 +++- Doc/whatsnew/3.14.rst | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 42162914c0aec8..886f1a2e4ec832 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -529,10 +529,12 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Exactly what values are considered compact is an implementation detail and is subject to change. -.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) +.. c:function:: int PyUnstable_Long_CompactValue(const PyLongObject* op) If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, return its value. Otherwise, the return value is undefined. + .. versionchanged:: 3.14 + Change return type from :c:type:`Py_ssize_t` to :c:type:`int`. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index d02c10ec9cf3f3..c7a37ed2dafde7 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -354,6 +354,10 @@ Porting to Python 3.14 an opaque function call to hide implementation details. (Contributed by Victor Stinner in :gh:`120600`.) +* Change :c:func:`PyUnstable_Long_CompactValue` return type from + :c:type:`Py_ssize_t` to :c:type:`int`. + (Contributed by Victor Stinner in :gh:`121153`.) + Deprecated ---------- From aac85d7eb2c876d1ee331bc9f41c219a8349f2fa Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 12 Jul 2024 18:59:05 +0200 Subject: [PATCH 10/11] doc: add "int" type --- Doc/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/conf.py b/Doc/conf.py index 29b1b2db32718b..6f9cb986596405 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -131,6 +131,7 @@ ('c:func', 'vsnprintf'), # Standard C types ('c:type', 'FILE'), + ('c:type', 'int'), ('c:type', 'int32_t'), ('c:type', 'int64_t'), ('c:type', 'intmax_t'), From 67d8d84b8c73dccace4af002810cceb59805ebe4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 12 Jul 2024 19:04:41 +0200 Subject: [PATCH 11/11] Fix doc --- Doc/c-api/long.rst | 2 +- Doc/conf.py | 1 - Doc/whatsnew/3.14.rst | 4 ++-- .../next/C_API/2024-07-12-19-06-02.gh-issue-121153.IIqFVF.rst | 3 +++ 4 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2024-07-12-19-06-02.gh-issue-121153.IIqFVF.rst diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 886f1a2e4ec832..cdb43b7dbd3d35 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -537,4 +537,4 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Otherwise, the return value is undefined. .. versionchanged:: 3.14 - Change return type from :c:type:`Py_ssize_t` to :c:type:`int`. + Change return type from :c:type:`Py_ssize_t` to ``int``. diff --git a/Doc/conf.py b/Doc/conf.py index 6f9cb986596405..29b1b2db32718b 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -131,7 +131,6 @@ ('c:func', 'vsnprintf'), # Standard C types ('c:type', 'FILE'), - ('c:type', 'int'), ('c:type', 'int32_t'), ('c:type', 'int64_t'), ('c:type', 'intmax_t'), diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c7a37ed2dafde7..09a9040caed706 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -355,8 +355,8 @@ Porting to Python 3.14 (Contributed by Victor Stinner in :gh:`120600`.) * Change :c:func:`PyUnstable_Long_CompactValue` return type from - :c:type:`Py_ssize_t` to :c:type:`int`. - (Contributed by Victor Stinner in :gh:`121153`.) + :c:type:`Py_ssize_t` to ``int``. + (Contributed by Serhiy Storchaka and Victor Stinner in :gh:`121153`.) Deprecated diff --git a/Misc/NEWS.d/next/C_API/2024-07-12-19-06-02.gh-issue-121153.IIqFVF.rst b/Misc/NEWS.d/next/C_API/2024-07-12-19-06-02.gh-issue-121153.IIqFVF.rst new file mode 100644 index 00000000000000..2bf4b018ad2092 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-07-12-19-06-02.gh-issue-121153.IIqFVF.rst @@ -0,0 +1,3 @@ +Change :c:func:`PyUnstable_Long_CompactValue` return type from +:c:type:`Py_ssize_t` to ``int``. Patch by Serhiy Storchaka and Victor +Stinner.