From 6978df97806054587bcaafed73bf2539dc7aa05a Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 25 Sep 2024 18:06:44 -0400 Subject: [PATCH 1/9] Fix integer limit for _curses.resizeterm() --- Lib/test/test_curses.py | 7 +++++ Modules/_cursesmodule.c | 8 ++--- Modules/clinic/_cursesmodule.c.h | 50 +++++++++++++++++++++++++------- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 83d10dd8579074..5466c7e1bdcfc8 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1095,6 +1095,13 @@ def test_resizeterm(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) + with self.assertRaises(OverflowError): + curses.resizeterm(35000, 1) + + # GH-120378: Overflow failure in resizeterm() causes refresh to fail + tmp = curses.initscr() + tmp.erase() + def test_ungetch(self): curses.ungetch(b'A') self.assertEqual(self.stdscr.getkey(), 'A') diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index c9ee5687c2b5d9..4061b171139d7d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4113,9 +4113,9 @@ NoArgNoReturnFunctionBody(resetty) /*[clinic input] _curses.resizeterm - nlines: int + nlines: short Height. - ncols: int + ncols: short Width. / @@ -4126,8 +4126,8 @@ window dimensions (in particular the SIGWINCH handler). [clinic start generated code]*/ static PyObject * -_curses_resizeterm_impl(PyObject *module, int nlines, int ncols) -/*[clinic end generated code: output=56d6bcc5194ad055 input=0fca02ebad5ffa82]*/ +_curses_resizeterm_impl(PyObject *module, short nlines, short ncols) +/*[clinic end generated code: output=4de3abab50c67f02 input=414e92a63e3e9899]*/ { PyObject *result; diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index f7e0aaf7b23649..5b0f9843cdee89 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -3693,25 +3693,55 @@ PyDoc_STRVAR(_curses_resizeterm__doc__, {"resizeterm", _PyCFunction_CAST(_curses_resizeterm), METH_FASTCALL, _curses_resizeterm__doc__}, static PyObject * -_curses_resizeterm_impl(PyObject *module, int nlines, int ncols); +_curses_resizeterm_impl(PyObject *module, short nlines, short ncols); static PyObject * _curses_resizeterm(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - int nlines; - int ncols; + short nlines; + short ncols; if (!_PyArg_CheckPositional("resizeterm", nargs, 2, 2)) { goto exit; } - nlines = PyLong_AsInt(args[0]); - if (nlines == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + nlines = (short) ival; + } } - ncols = PyLong_AsInt(args[1]); - if (ncols == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + ncols = (short) ival; + } } return_value = _curses_resizeterm_impl(module, nlines, ncols); @@ -4318,4 +4348,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=96887782374f070a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=acf9090d9bd82d3f input=a9049054013a1b77]*/ From a2fbe58d567a1195846d9515695d030bb830a3fc Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 25 Sep 2024 18:07:58 -0400 Subject: [PATCH 2/9] Add NEWS entry. --- .../next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst new file mode 100644 index 00000000000000..1570c02d8c6efd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst @@ -0,0 +1 @@ +Fix crash related to integer overflow in :func:`curses.resizeterm` From 93eec97693c495fe0eb506d6edfcfc7837f7dbb0 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 10:23:58 -0400 Subject: [PATCH 3/9] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_curses.py | 3 ++- .../Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 5466c7e1bdcfc8..70fe8c4dfef5ef 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1097,7 +1097,8 @@ def test_resizeterm(self): with self.assertRaises(OverflowError): curses.resizeterm(35000, 1) - + with self.assertRaises(OverflowError): + curses.resizeterm(1, 35000) # GH-120378: Overflow failure in resizeterm() causes refresh to fail tmp = curses.initscr() tmp.erase() diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst index 1570c02d8c6efd..81195a4dc80528 100644 --- a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst +++ b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst @@ -1 +1 @@ -Fix crash related to integer overflow in :func:`curses.resizeterm` +Fix a crash related to an integer overflow in :func:`curses.resizeterm`. From fc63d6a9fb68dcd9a9d772319c9a3ceb6289b136 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 10:26:55 -0400 Subject: [PATCH 4/9] Test for resizeterm() and resize_term() --- Lib/test/test_curses.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 70fe8c4dfef5ef..6cc306352644c2 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1095,13 +1095,15 @@ def test_resizeterm(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) - with self.assertRaises(OverflowError): - curses.resizeterm(35000, 1) - with self.assertRaises(OverflowError): - curses.resizeterm(1, 35000) - # GH-120378: Overflow failure in resizeterm() causes refresh to fail - tmp = curses.initscr() - tmp.erase() + for func in (curses.resizeterm, curses.resize_term): + with self.subTest(func=func): + with self.assertRaises(OverflowError): + curses.resizeterm(35000, 1) + with self.assertRaises(OverflowError): + curses.resizeterm(1, 35000) + # GH-120378: Overflow failure in resizeterm() causes refresh to fail + tmp = curses.initscr() + tmp.erase() def test_ungetch(self): curses.ungetch(b'A') From db82f15faa20fa100d39db0cb1b0866747ef2f94 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 11:38:56 -0400 Subject: [PATCH 5/9] Update Lib/test/test_curses.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_curses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 6cc306352644c2..0a886360863143 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1098,9 +1098,9 @@ def test_resizeterm(self): for func in (curses.resizeterm, curses.resize_term): with self.subTest(func=func): with self.assertRaises(OverflowError): - curses.resizeterm(35000, 1) + func(35000, 1) with self.assertRaises(OverflowError): - curses.resizeterm(1, 35000) + func(1, 35000) # GH-120378: Overflow failure in resizeterm() causes refresh to fail tmp = curses.initscr() tmp.erase() From a79bd5148068233b78e5afbb5d6eea87642f8e03 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 11:57:40 -0400 Subject: [PATCH 6/9] Fix tests. --- Lib/test/test_curses.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 0a886360863143..fee83f620acea6 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1081,6 +1081,14 @@ def test_resize_term(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) + with self.assertRaises(OverflowError): + curses.resize_term(35000, 1) + with self.assertRaises(OverflowError): + curses.resize_term(1, 35000) + # GH-120378: Overflow failure in resizeterm() causes refresh to fail + tmp = curses.initscr() + tmp.erase() + @requires_curses_func('resizeterm') def test_resizeterm(self): curses.update_lines_cols() @@ -1095,15 +1103,13 @@ def test_resizeterm(self): self.assertEqual(curses.LINES, lines) self.assertEqual(curses.COLS, cols) - for func in (curses.resizeterm, curses.resize_term): - with self.subTest(func=func): - with self.assertRaises(OverflowError): - func(35000, 1) - with self.assertRaises(OverflowError): - func(1, 35000) - # GH-120378: Overflow failure in resizeterm() causes refresh to fail - tmp = curses.initscr() - tmp.erase() + with self.assertRaises(OverflowError): + curses.resizeterm(35000, 1) + with self.assertRaises(OverflowError): + curses.resizeterm(1, 35000) + # GH-120378: Overflow failure in resizeterm() causes refresh to fail + tmp = curses.initscr() + tmp.erase() def test_ungetch(self): curses.ungetch(b'A') From 679161d41c108eb86d34656c748fdd233e81987d Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 12:00:23 -0400 Subject: [PATCH 7/9] Update Lib/test/test_curses.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_curses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index fee83f620acea6..cc3aa561cd4c42 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1085,7 +1085,7 @@ def test_resize_term(self): curses.resize_term(35000, 1) with self.assertRaises(OverflowError): curses.resize_term(1, 35000) - # GH-120378: Overflow failure in resizeterm() causes refresh to fail + # GH-120378: Overflow failure in resize_term() causes refresh to fail tmp = curses.initscr() tmp.erase() From 229e5756f93d5cf32d516bcee3fa6ca5bb5d182b Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 12:02:52 -0400 Subject: [PATCH 8/9] Run clinic for resize_term() --- Modules/_cursesmodule.c | 8 ++--- Modules/clinic/_cursesmodule.c.h | 50 +++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4061b171139d7d..c9ae20304b2385 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4149,9 +4149,9 @@ _curses_resizeterm_impl(PyObject *module, short nlines, short ncols) /*[clinic input] _curses.resize_term - nlines: int + nlines: short Height. - ncols: int + ncols: short Width. / @@ -4165,8 +4165,8 @@ without additional interaction with the application. [clinic start generated code]*/ static PyObject * -_curses_resize_term_impl(PyObject *module, int nlines, int ncols) -/*[clinic end generated code: output=9e26d8b9ea311ed2 input=2197edd05b049ed4]*/ +_curses_resize_term_impl(PyObject *module, short nlines, short ncols) +/*[clinic end generated code: output=46c6d749fa291dbd input=276afa43d8ea7091]*/ { PyObject *result; diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 5b0f9843cdee89..0b52308f10243e 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -3774,25 +3774,55 @@ PyDoc_STRVAR(_curses_resize_term__doc__, {"resize_term", _PyCFunction_CAST(_curses_resize_term), METH_FASTCALL, _curses_resize_term__doc__}, static PyObject * -_curses_resize_term_impl(PyObject *module, int nlines, int ncols); +_curses_resize_term_impl(PyObject *module, short nlines, short ncols); static PyObject * _curses_resize_term(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - int nlines; - int ncols; + short nlines; + short ncols; if (!_PyArg_CheckPositional("resize_term", nargs, 2, 2)) { goto exit; } - nlines = PyLong_AsInt(args[0]); - if (nlines == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[0]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + nlines = (short) ival; + } } - ncols = PyLong_AsInt(args[1]); - if (ncols == -1 && PyErr_Occurred()) { - goto exit; + { + long ival = PyLong_AsLong(args[1]); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + goto exit; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + goto exit; + } + else { + ncols = (short) ival; + } } return_value = _curses_resize_term_impl(module, nlines, ncols); @@ -4348,4 +4378,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=acf9090d9bd82d3f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8745c1562b537fb4 input=a9049054013a1b77]*/ From b70a042f41261dc908e62d24698cd9eb8559b1a9 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 29 Sep 2024 12:08:47 -0400 Subject: [PATCH 9/9] Update Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst index 81195a4dc80528..1a8c1427b6b9b9 100644 --- a/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst +++ b/Misc/NEWS.d/next/Library/2024-09-25-18-07-51.gh-issue-120378.NlBSz_.rst @@ -1 +1,2 @@ -Fix a crash related to an integer overflow in :func:`curses.resizeterm`. +Fix a crash related to an integer overflow in :func:`curses.resizeterm` +and :func:`curses.resize_term`.