From 5a6872f96056d14b75c81e41343a39ecc9a487b9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 29 Jun 2024 17:29:33 +0300 Subject: [PATCH 1/4] gh-121153: Fix some errors with use of _PyLong_CompactValue() * The result has type Py_ssize_t, not intptr_t. * Type cast between unsigned and signdet integer types should be explicit. * Downcasting should be explicit. --- Objects/longobject.c | 57 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 4ca259fb08e8c7..44bf8848829f11 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -483,11 +483,14 @@ 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) { +#if SIZEOF_LONG < SIZEOF_SIZE_T + Py_ssize_t tmp = _PyLong_CompactValue(v); + if ((unsigned long)(size_t)tmp != (size_t)tmp) { *overflow = tmp < 0 ? -1 : 1; + res = -1; + } + else { + res = (long)tmp; } #else res = _PyLong_CompactValue(v); @@ -632,14 +635,14 @@ 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_LONG < SIZEOF_SIZE_T + size_t tmp = (size_t)_PyLong_CompactValue(v); unsigned long res = (unsigned long)tmp; if (res != tmp) { goto overflow; } #else - return _PyLong_CompactValue(v); + return (unsigned long)(size_t)_PyLong_CompactValue(v); #endif } if (_PyLong_IsNegative(v)) { @@ -685,7 +688,7 @@ PyLong_AsSize_t(PyObject *vv) v = (PyLongObject *)vv; if (_PyLong_IsNonNegativeCompact(v)) { - return _PyLong_CompactValue(v); + return (size_t)_PyLong_CompactValue(v); } if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, @@ -722,7 +725,11 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long)_PyLong_CompactValue(v); +#if SIZEOF_LONG < SIZEOF_SIZE_T + return (unsigned long)(size_t)_PyLong_CompactValue(v); +#else + return (unsigned long)(long)_PyLong_CompactValue(v); +#endif } i = _PyLong_DigitCount(v); int sign = _PyLong_NonCompactSign(v); @@ -1540,7 +1547,18 @@ PyLong_AsUnsignedLongLong(PyObject *vv) v = (PyLongObject*)vv; if (_PyLong_IsNonNegativeCompact(v)) { res = 0; - bytes = _PyLong_CompactValue(v); +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + size_t tmp = (size_t)_PyLong_CompactValue(v); + bytes = (unsigned long long)tmp; + if (bytes != tmp) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C unsigned long long"); + res = -1; + } +#else + bytes = (unsigned long long)(size_t)_PyLong_CompactValue(v); +#endif } else { res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, @@ -1571,7 +1589,11 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) } v = (PyLongObject *)vv; if (_PyLong_IsCompact(v)) { - return (unsigned long long)(signed long long)_PyLong_CompactValue(v); +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + return (unsigned long long)(size_t)_PyLong_CompactValue(v); +#else + return (unsigned long long)(long long)_PyLong_CompactValue(v); +#endif } i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); @@ -1643,7 +1665,18 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) do_decref = 1; } if (_PyLong_IsCompact(v)) { +#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T + Py_ssize_t tmp = _PyLong_CompactValue(v); + if ((unsigned long long)(size_t)tmp != (size_t)tmp) { + *overflow = tmp < 0 ? -1 : 1; + res = -1; + } + else { + res = (long long)tmp; + } +#else res = _PyLong_CompactValue(v); +#endif } else { i = _PyLong_DigitCount(v); @@ -3579,7 +3612,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; } From 576770fd9713fcccf8110697f431134dfe416ac3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 29 Jun 2024 23:09:19 +0300 Subject: [PATCH 2/4] Fix PyLong_AsUnsignedLong. --- Objects/longobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/longobject.c b/Objects/longobject.c index 44bf8848829f11..944ad6c154e3c4 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -641,6 +641,7 @@ PyLong_AsUnsignedLong(PyObject *vv) if (res != tmp) { goto overflow; } + return res; #else return (unsigned long)(size_t)_PyLong_CompactValue(v); #endif From 940acfa836293085720f38ed219127198b642f2f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 30 Jun 2024 00:03:05 +0300 Subject: [PATCH 3/4] Fix PyLong_AsLongAndOverflow. --- Objects/longobject.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 944ad6c154e3c4..ace01ddeb37f66 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -485,8 +485,12 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) if (_PyLong_IsCompact(v)) { #if SIZEOF_LONG < SIZEOF_SIZE_T Py_ssize_t tmp = _PyLong_CompactValue(v); - if ((unsigned long)(size_t)tmp != (size_t)tmp) { - *overflow = tmp < 0 ? -1 : 1; + if (tmp < LONG_MIN) { + *overflow = -1; + res = -1; + } + else if (tmp > LONG_MAX) { + *overflow = 1; res = -1; } else { @@ -1668,8 +1672,12 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) if (_PyLong_IsCompact(v)) { #if SIZEOF_LONG_LONG < SIZEOF_SIZE_T Py_ssize_t tmp = _PyLong_CompactValue(v); - if ((unsigned long long)(size_t)tmp != (size_t)tmp) { - *overflow = tmp < 0 ? -1 : 1; + if (tmp < LLONG_MIN) { + *overflow = -1; + res = -1; + } + else if (tmp > LLONG_MAX) { + *overflow = 1; res = -1; } else { From e186e79afbd93739b3df63b0877809c9909a7421 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 13 Jul 2024 13:06:57 +0300 Subject: [PATCH 4/4] Fix also integer overflow check in sum(). --- Python/bltinmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 6e50623cafa4ed..34f1f0d94c5118 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2601,8 +2601,8 @@ 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 ? (b <= PY_SSIZE_T_MAX - i_result) + : (b >= PY_SSIZE_T_MIN - i_result))) { i_result += b; Py_DECREF(item);