diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index cd3ee48a92..ae1254945d 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1237,6 +1237,14 @@ class MixinStrUnicodeUserStringTest: (PY_SSIZE_T_MAX + 1, '')) self.checkraises(OverflowError, '%.*f', '__mod__', (INT_MAX + 1, 1. / 7)) + + self.checkraises(OverflowError, '%c', '__mod__', -1 << 1000) + self.checkraises(OverflowError, '%c', '__mod__', -1) + self.checkequal('c=\x00', 'c=%c', '__mod__', 0) + self.checkequal('c=\U0010ffff', 'c=%c', '__mod__', 0x10ffff) + self.checkraises(OverflowError, '%c', '__mod__', 0x110000) + self.checkraises(OverflowError, '%c', '__mod__', 1 << 1000) + # Issue 15989 self.checkraises(OverflowError, '%*s', '__mod__', (SIZE_MAX + 1, '')) diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index fd15f04ace..aca5aaaba0 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -712,6 +712,14 @@ class LongTest(unittest.TestCase): self.assertEqual(format(value, format_spec), format(float(value), format_spec)) + # test 'c' specifier limits + self.assertRaises(OverflowError, format, -1 << 1000, 'c') + self.assertRaises(OverflowError, format, -1, 'c') + self.assertEqual(format(0, 'c'), '\x00') + self.assertEqual(format(0x10ffff, 'c'), '\U0010ffff') + self.assertRaises(OverflowError, format, 0x110000, 'c') + self.assertRaises(OverflowError, format, 1 << 1000, 'c') + def test_nan_inf(self): self.assertRaises(OverflowError, int, float('inf')) self.assertRaises(OverflowError, int, float('-inf')) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 503a59e1ef..12228fd572 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14373,6 +14373,7 @@ wrongtype: static Py_UCS4 formatchar(PyObject *v) { + int overflow; /* presume that the buffer is at least 3 characters long */ if (PyUnicode_Check(v)) { if (PyUnicode_GET_LENGTH(v) == 1) { @@ -14389,16 +14390,17 @@ formatchar(PyObject *v) if (iobj == NULL) { goto onError; } - x = PyLong_AsLong(iobj); + x = PyLong_AsLongAndOverflow(iobj, &overflow); Py_DECREF(iobj); } else { - x = PyLong_AsLong(v); + x = PyLong_AsLongAndOverflow(v, &overflow); } - if (x == -1 && PyErr_Occurred()) - goto onError; + /* either PyLong_Check(v) or PyLong_Check(iobj) is true, so it is + guaranteed that no error occurred in PyLong_AsLongAndOverflow. */ + assert(!(x == -1 && PyErr_Occurred())); - if (x < 0 || x > MAX_UNICODE) { + if (overflow || x < 0 || x > MAX_UNICODE) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); return (Py_UCS4) -1; diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index a2c2b3627c..f20d077e14 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -860,6 +860,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, Py_ssize_t prefix = 0; NumberFieldWidths spec; long x; + int overflow; /* Locale settings, either from the actual locale or from a hard-code pseudo-locale */ @@ -889,12 +890,12 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, goto done; } - /* taken from unicodeobject.c formatchar() */ /* Integer input truncated to a character */ - x = PyLong_AsLong(value); - if (x == -1 && PyErr_Occurred()) + x = PyLong_AsLongAndOverflow(value, &overflow); + if (x == -1 && PyErr_Occurred()) { goto done; - if (x < 0 || x > 0x10ffff) { + } + if (overflow || x < 0 || x > 0x10ffff) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); goto done;