From d63235b9e9edf679ed528846c9f8541ce86cc394 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 22 Jan 2025 13:07:15 +0530 Subject: [PATCH 1/3] Create a macro PYLONG_FROM_SIGNED, and leverage it in functions PyLong_FromLong, PyLong_FromLongLong and PyLong_FromSsize_t so the repetitive code is removed. --- Objects/longobject.c | 144 ++++++++++++------------------------------- 1 file changed, 40 insertions(+), 104 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 370931e64d3627..ff227d86118067 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -115,6 +115,43 @@ maybe_small_long(PyLongObject *v) if (PyErr_CheckSignals()) PyTryBlock \ } while(0) +#define PYLONG_FROM_SIGNED(INT_TYPE, ival) \ + do { \ + if (IS_SMALL_INT(ival)) { \ + return get_small_int((sdigit)(ival)); \ + } \ + if (-(INT_TYPE)PyLong_MASK <= (ival) && (ival) <= (INT_TYPE)PyLong_MASK) { \ + return _PyLong_FromMedium((sdigit)(ival)); \ + } \ + /* Count digits (at least two - smaller cases were handled above). */ \ + size_t abs_ival, t; /* Use size_t for unsigned operations */ \ + if ((ival) < 0) { \ + /* avoid signed overflow when ival = minimum value */ \ + abs_ival = (size_t)(-1-(ival))+1; \ + } else { \ + abs_ival = (size_t)(ival); \ + } \ + /* Do shift in two steps to avoid possible undefined behavior. */ \ + t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT; \ + Py_ssize_t ndigits = 2; \ + while (t) { \ + ++ndigits; \ + t >>= PyLong_SHIFT; \ + } \ + PyLongObject *v = _PyLong_New(ndigits); \ + if (v == NULL) { \ + return NULL; \ + } \ + digit *p = v->long_value.ob_digit; \ + _PyLong_SetSignAndDigitCount(v, (ival) < 0 ? -1 : 1, ndigits); \ + t = abs_ival; \ + while (t) { \ + *p++ = (digit)(t & PyLong_MASK); \ + t >>= PyLong_SHIFT; \ + } \ + return (PyObject *)v; \ + } while(0) + /* Normalize (remove leading zeros from) an int object. Doesn't attempt to free the storage--in most cases, due to the nature of the algorithms used, this could save at most be one word anyway. */ @@ -318,40 +355,7 @@ _PyLong_Negate(PyLongObject **x_p) PyObject * PyLong_FromLong(long ival) { - PyLongObject *v; - unsigned long abs_ival, t; - int ndigits; - - /* Handle small and medium cases. */ - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } - if (-(long)PyLong_MASK <= ival && ival <= (long)PyLong_MASK) { - return _PyLong_FromMedium((sdigit)ival); - } - - /* Count digits (at least two - smaller cases were handled above). */ - abs_ival = ival < 0 ? 0U-(unsigned long)ival : (unsigned long)ival; - /* Do shift in two steps to avoid possible undefined behavior. */ - t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT; - ndigits = 2; - while (t) { - ++ndigits; - t >>= PyLong_SHIFT; - } - - /* Construct output value. */ - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); - t = abs_ival; - while (t) { - *p++ = (digit)(t & PyLong_MASK); - t >>= PyLong_SHIFT; - } - } - return (PyObject *)v; + PYLONG_FROM_SIGNED(long, ival); } #define PYLONG_FROM_UINT(INT_TYPE, ival) \ @@ -1459,40 +1463,7 @@ PyLong_AsVoidPtr(PyObject *vv) PyObject * PyLong_FromLongLong(long long ival) { - PyLongObject *v; - unsigned long long abs_ival, t; - int ndigits; - - /* Handle small and medium cases. */ - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } - if (-(long long)PyLong_MASK <= ival && ival <= (long long)PyLong_MASK) { - return _PyLong_FromMedium((sdigit)ival); - } - - /* Count digits (at least two - smaller cases were handled above). */ - abs_ival = ival < 0 ? 0U-(unsigned long long)ival : (unsigned long long)ival; - /* Do shift in two steps to avoid possible undefined behavior. */ - t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT; - ndigits = 2; - while (t) { - ++ndigits; - t >>= PyLong_SHIFT; - } - - /* Construct output value. */ - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); - t = abs_ival; - while (t) { - *p++ = (digit)(t & PyLong_MASK); - t >>= PyLong_SHIFT; - } - } - return (PyObject *)v; + PYLONG_FROM_SIGNED(long long, ival); } /* Create a new int object from a C Py_ssize_t. */ @@ -1500,42 +1471,7 @@ PyLong_FromLongLong(long long ival) PyObject * PyLong_FromSsize_t(Py_ssize_t ival) { - PyLongObject *v; - size_t abs_ival; - size_t t; /* unsigned so >> doesn't propagate sign bit */ - int ndigits = 0; - int negative = 0; - - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } - - if (ival < 0) { - /* avoid signed overflow when ival = SIZE_T_MIN */ - abs_ival = (size_t)(-1-ival)+1; - negative = 1; - } - else { - abs_ival = (size_t)ival; - } - - /* Count the number of Python digits. */ - t = abs_ival; - while (t) { - ++ndigits; - t >>= PyLong_SHIFT; - } - v = _PyLong_New(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); - t = abs_ival; - while (t) { - *p++ = (digit)(t & PyLong_MASK); - t >>= PyLong_SHIFT; - } - } - return (PyObject *)v; + PYLONG_FROM_SIGNED(Py_ssize_t, ival); } /* Get a C long long int from an int object or any object that has an From ce8b48ee6039b1c79cf7bd024fd8e0ce01529faf Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Thu, 23 Jan 2025 15:17:38 +0530 Subject: [PATCH 2/3] Handle minimum case separately --- Objects/longobject.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index ff227d86118067..0d4a442cd216cb 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -124,10 +124,15 @@ maybe_small_long(PyLongObject *v) return _PyLong_FromMedium((sdigit)(ival)); \ } \ /* Count digits (at least two - smaller cases were handled above). */ \ - size_t abs_ival, t; /* Use size_t for unsigned operations */ \ + size_t abs_ival; /* Use size_t for unsigned operations */ \ + size_t t; \ if ((ival) < 0) { \ - /* avoid signed overflow when ival = minimum value */ \ - abs_ival = (size_t)(-1-(ival))+1; \ + /* Handle minimum value case separately to avoid overflow */ \ + if ((ival) == -(INT_TYPE)((size_t)1 << (sizeof(INT_TYPE) * 8 - 1))) { \ + abs_ival = (size_t)1 << (sizeof(INT_TYPE) * 8 - 1); \ + } else { \ + abs_ival = (size_t)(-(ival)); \ + } \ } else { \ abs_ival = (size_t)(ival); \ } \ From a6cef093026d3a4265b15c8b96fe7c68c3125a88 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Thu, 23 Jan 2025 15:25:51 +0530 Subject: [PATCH 3/3] Fix compiler warnings --- Objects/longobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 0d4a442cd216cb..62e296f0328e7c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -128,8 +128,8 @@ maybe_small_long(PyLongObject *v) size_t t; \ if ((ival) < 0) { \ /* Handle minimum value case separately to avoid overflow */ \ - if ((ival) == -(INT_TYPE)((size_t)1 << (sizeof(INT_TYPE) * 8 - 1))) { \ - abs_ival = (size_t)1 << (sizeof(INT_TYPE) * 8 - 1); \ + if ((size_t)(ival) == ((size_t)1 << (sizeof(INT_TYPE) * 8 - 1))) { \ + abs_ival = ((size_t)1 << (sizeof(INT_TYPE) * 8 - 1)); \ } else { \ abs_ival = (size_t)(-(ival)); \ } \