From 0f611aca8f3e372cefcfa5497f49b30b9b9eba7b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 15 Nov 2026 12:13:25 +0100 Subject: [PATCH] Rework PyLong import/export functions * Only call _PyLong_GetDigits() once in PyLongWriter_Finish(). * _PyLong_DigitCount() now uses Py_ABS(Py_SIZE(obj)). * Enhance PyLong_Export() tests: test negative value and test PyObject_Str(). --- pythoncapi_compat.h | 8 +++++--- tests/test_pythoncapi_compat_cext.c | 11 ++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 3fee8d2..a3521d4 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -2064,7 +2064,8 @@ _PyLong_DigitCount(const PyLongObject *op) #if PY_VERSION_HEX >= _Py_PACK_VERSION(3, 12) return (Py_ssize_t)(op->long_value.lv_tag >> 3); #else - return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op); + Py_ssize_t size = Py_SIZE(op); + return Py_ABS(size); #endif } @@ -2201,7 +2202,8 @@ PyLongWriter_Finish(PyLongWriter *writer) assert(Py_REFCNT(obj) == 1); // Normalize and get singleton if possible - while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) { + digit *digits = _PyLong_GetDigits(self); + while (i > 0 && digits[i-1] == 0) { --i; } if (i != j) { @@ -2211,7 +2213,7 @@ PyLongWriter_Finish(PyLongWriter *writer) _PyLong_SetSignAndDigitCount(self, sign, i); } if (i <= 1) { - long val = sign * (long)(_PyLong_GetDigits(self)[0]); + long val = sign * (long)digits[0]; Py_DECREF(obj); return PyLong_FromLong(val); } diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 0f8039b..c75005b 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -1457,11 +1457,13 @@ test_long_import_export() return -1; } assert(long_export.value == -123); + assert(long_export.negative == 0); + assert(long_export.ndigits == 0); assert(long_export.digits == NULL); PyLong_FreeExport(&long_export); Py_DECREF(obj); - writer = PyLongWriter_Create(0, 5, (void **)&digits); + writer = PyLongWriter_Create(1, 5, (void **)&digits); if (writer == NULL) { return -1; } @@ -1475,10 +1477,17 @@ test_long_import_export() return -1; } + PyObject *str = PyObject_Str(obj); + assert(str != NULL); + assert(PyUnicode_EqualToUTF8(str, "-1329227995784915872903807060280344577") == 1); + Py_DECREF(str); + if (PyLong_Export(obj, &long_export) < 0) { return -1; } assert(long_export.value == 0); + assert(long_export.negative == 1); + assert(long_export.ndigits == 5); digits = (uint32_t*)long_export.digits; assert(digits[0] == 1); assert(digits[1] == 0);