From 7e9550601990dd3b891e048dc3d9d76962e0e146 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 21 Oct 2026 21:29:33 -0700 Subject: [PATCH 1/2] gh-159739: Propagate float rounding allocation failures If the decimal-to-binary conversion inside round(float, ndigits) runs out of memory, it returns a -1.0 error sentinel and sets errno to ENOMEM. Ignoring that error can return -1.0 as a seemingly successful rounded value. Raise MemoryError instead. Backport to 3.15 and 3.14. --- .../2026-10-21-21-26-10.gh-issue-159739.Zw43uX.rst | 1 + Objects/floatobject.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-21-26-10.gh-issue-159739.Zw43uX.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-21-26-10.gh-issue-159739.Zw43uX.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-21-26-10.gh-issue-159739.Zw43uX.rst new file mode 100644 index 000000000000000..628a146b059a436 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-21-26-10.gh-issue-159739.Zw43uX.rst @@ -0,0 +1 @@ +Raise :exc:`MemoryError` instead of returning an incorrect result if :func:`round` runs out of memory while rounding a float. diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d5a879cdd53ad62..7c2cf549a4615cb 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -942,7 +942,9 @@ double_round(double x, int ndigits) { _Py_SET_53BIT_PRECISION_START; rounded = _Py_dg_strtod(mybuf, NULL); _Py_SET_53BIT_PRECISION_END; - if (errno == ERANGE && fabs(rounded) >= 1.) + if (errno == ENOMEM) + PyErr_NoMemory(); + else if (errno == ERANGE && fabs(rounded) >= 1.) PyErr_SetString(PyExc_OverflowError, "rounded value too large to represent"); else From af72bd06949b2309ab47706d385814cbf0b604f3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 22 Oct 2026 10:43:53 -0700 Subject: [PATCH 2/2] gh-159739: Use braces in float rounding error handling The float rounding allocation-failure check extended an unbraced conditional chain, contrary to the C style required for modified code. Add braces to its branches without changing their behavior. Backport to 3.15 and 3.14. --- Objects/floatobject.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7c2cf549a4615cb..c19ed6e6b609352 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -942,13 +942,16 @@ double_round(double x, int ndigits) { _Py_SET_53BIT_PRECISION_START; rounded = _Py_dg_strtod(mybuf, NULL); _Py_SET_53BIT_PRECISION_END; - if (errno == ENOMEM) + if (errno == ENOMEM) { PyErr_NoMemory(); - else if (errno == ERANGE && fabs(rounded) >= 1.) + } + else if (errno == ERANGE && fabs(rounded) >= 1.) { PyErr_SetString(PyExc_OverflowError, "rounded value too large to represent"); - else + } + else { result = PyFloat_FromDouble(rounded); + } /* done computing value; now clean up */ if (mybuf != shortbuf)