10000 gh-134209: use heap-allocated memory in `_curses.window.{instr,getstr… · python/cpython@aadda87 · GitHub
[go: up one dir, main page]

Skip to content

Commit aadda87

Browse files
zydtigerblurb-it[bot]gpsheadpicnixz
authored
gh-134209: use heap-allocated memory in _curses.window.{instr,getstr} (GH-134283)
* made curses buffer heap allocated instead of stack * change docs to explicitly mention the max buffer size * changing GetStr() function to behave similarly too * Update Doc/library/curses.rst * Update instr with proper return error handling * Update Modules/_cursesmodule.c * change to strlen and better memory safety * change from const int to Py_ssize_t * add mem allocation guard * update versionchanged to mention it was an increase. * explicitly use versionchanged 3.14 as that is its own branch now. TESTED: `python -m test -u curses test_curses` --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent a3a3cf6 commit aadda87

File tree

3 files changed

+80
-33
lines changed

3 files changed

+80
-33
lines changed

Doc/library/curses.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,10 @@ the following methods and attributes:
988988
window.getstr(y, x, n)
989989

990990
Read a bytes object from the user, with primitive line editing capacity.
991+
The maximum value for *n* is 2047.
992+
993+
.. versionchanged:: 3.14
994+
The maximum value for *n* was increased from 1023 to 2047.
991995

992996

993997
.. method:: window.getyx()
@@ -1079,6 +1083,10 @@ the following methods and attributes:
10791083
current cursor position, or at *y*, *x* if specified. Attributes are stripped
10801084
from the characters. If *n* is specified, :meth:`instr` returns a string
10811085
at most *n* characters long (exclusive of the trailing NUL).
1086+
The maximum value for *n* is 2047.
1087+
1088+
.. versionchanged:: 3.14
1089+
The maximum value for *n* was increased from 1023 to 2047.
10821090

10831091

10841092
.. method:: window.is_linetouched(line)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`curses`: The :meth:`curses.window.instr` and :meth:`curses.window.getstr`
2+
methods now allocate their internal buffer on the heap instead of the stack;
3+
in addition, the max buffer size is increased from 1023 to 2047.

Modules/_cursesmodule.c

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ _curses.window.getstr
18161816
x: int
18171817
X-coordinate.
18181818
]
1819-
n: int = 1023
1819+
n: int = 2047
18201820
Maximal number of characters.
18211821
/
18221822
@@ -1829,62 +1829,80 @@ PyCursesWindow_GetStr(PyObject *op, PyObject *args)
18291829
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
18301830

18311831
int x, y, n;
1832-
char rtn[1024]; /* This should be big enough.. I hope */
1833-
int rtn2;
1832+
int rtn;
1833+
1834+
/* could make the buffer size larger/dynamic */
1835+
Py_ssize_t max_buf_size = 2048;
1836+
PyObject *result = PyBytes_FromStringAndSize(NULL, max_buf_size);
1837+
if (result == NULL)
1838+
return NULL;
1839+
char *buf = PyBytes_AS_STRING(result);
18341840

18351841
switch (PyTuple_Size(args)) {
18361842
case 0:
18371843
Py_BEGIN_ALLOW_THREADS
1838-
rtn2 = wgetnstr(self->win,rtn, 1023);
1844+
rtn = wgetnstr(self->win, buf, max_buf_size - 1);
18391845
Py_END_ALLOW_THREADS
18401846
break;
18411847
case 1:
18421848
if (!PyArg_ParseTuple(args,"i;n", &n))
1843-
return NULL;
1849+
goto error;
18441850
if (n < 0) {
18451851
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
1846-
return NULL;
1852+
goto error;
18471853
}
18481854
Py_BEGIN_ALLOW_THREADS
1849-
rtn2 = wgetnstr(self->win, rtn, Py_MIN(n, 1023));
1855+
rtn = wgetnstr(self->win, buf, Py_MIN(n, max_buf_size - 1));
18501856
Py_END_ALLOW_THREADS
18511857
break;
18521858
case 2:
18531859
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
1854-
return NULL;
1860+
goto error;
18551861
Py_BEGIN_ALLOW_THREADS
18561862
#ifdef STRICT_SYSV_CURSES
1857-
rtn2 = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, 1023);
1863+
rtn = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, max_buf_size - 1);
18581864
#else
1859-
rtn2 = mvwgetnstr(self->win,y,x,rtn, 1023);
1865+
rtn = mvwgetnstr(self->win,y,x,buf, max_buf_size - 1);
18601866
#endif
18611867
Py_END_ALLOW_THREADS
18621868
break;
18631869
case 3:
18641870
if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n))
1865-
return NULL;
1871+
goto error;
18661872
if (n < 0) {
18671873
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
1868-
return NULL;
1874+
goto error;
18691875
}
18701876
#ifdef STRICT_SYSV_CURSES
18711877
Py_BEGIN_ALLOW_THREADS
1872-
rtn2 = wmove(self->win,y,x)==ERR ? ERR :
1873-
wgetnstr(self->win, rtn, Py_MIN(n, 1023));
1878+
rtn = wmove(self->win,y,x)==ERR ? ERR :
1879+
wgetnstr(self->win, rtn, Py_MIN(n, max_buf_size - 1));
18741880
Py_END_ALLOW_THREADS
18751881
#else
18761882
Py_BEGIN_ALLOW_THREADS
1877-
rtn2 = mvwgetnstr(self->win, y, x, rtn, Py_MIN(n, 1023));
1883+
rtn = mvwgetnstr(self->win, y, x, buf, Py_MIN(n, max_buf_size - 1));
18781884
Py_END_ALLOW_THREADS
18791885
#endif
18801886
break;
18811887
default:
18821888
PyErr_SetString(PyExc_TypeError, "getstr requires 0 to 3 arguments");
1889+
goto error;
1890+
}
1891+
1892+
if (rtn == ERR) {
1893+
Py_DECREF(result);
1894+
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
1895+
}
1896+
1897+
if (_PyBytes_Resize(&result, strlen(buf)) < 0) {
18831898
return NULL;
18841899
}
1885-
if (rtn2 == ERR)
1886-
rtn[0] = 0;
1887-
return PyBytes_FromString(rtn);
1900+
1901+
return result;
1902+
1903+
error:
1904+
Py_DECREF(result);
1905+
return NULL;
18881906
}
18891907

18901908
/*[clinic input]
@@ -2023,7 +2041,7 @@ _curses.window.instr
20232041
x: int
2024204 10000 2
X-coordinate.
20252043
]
2026-
n: int = 1023
2044+
n: int = 2047
20272045
Maximal number of characters.
20282046
/
20292047
@@ -2040,43 +2058,61 @@ PyCursesWindow_InStr(PyObject *op, PyObject *args)
20402058
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
20412059

20422060
int x, y, n;
2043-
char rtn[1024]; /* This should be big enough.. I hope */
2044-
int rtn2;
2061+
int rtn;
2062+
2063+
/* could make the buffer size larger/dynamic */
2064+
Py_ssize_t max_buf_size = 2048;
2065+
PyObject *result = PyBytes_FromStringAndSize(NULL, max_buf_size);
2066+
if (result == NULL)
2067+
return NULL;
2068+
char *buf = PyBytes_AS_STRING(result);
20452069

20462070
switch (PyTuple_Size(args)) {
20472071
case 0:
2048-
rtn2 = winnstr(self->win,rtn, 1023);
2072+
rtn = winnstr(self->win, buf, max_buf_size - 1);
20492073
break;
20502074
case 1:
20512075
if (!PyArg_ParseTuple(args,"i;n", &n))
2052-
return NULL;
2076+
goto error;
20532077
if (n < 0) {
20542078
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
2055-
return NULL;
2079+
goto error;
20562080
}
2057-
rtn2 = winnstr(self->win, rtn, Py_MIN(n, 1023));
2081+
rtn = winnstr(self->win, buf, Py_MIN(n, max_buf_size - 1));
20582082
break;
20592083
case 2:
20602084
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
2061-
return NULL;
2062-
rtn2 = mvwinnstr(self->win,y,x,rtn,1023);
2085+
goto error;
2086+
rtn = mvwinnstr(self->win, y, x, bu 6377 f, max_buf_size - 1);
20632087
break;
20642088
case 3:
20652089
if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n))
2066-
return NULL;
2090+
goto error;
20672091
if (n < 0) {
20682092
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
2069-
return NULL;
2093+
goto error;
20702094
}
2071-
rtn2 = mvwinnstr(self->win, y, x, rtn, Py_MIN(n,1023));
2095+
rtn = mvwinnstr(self->win, y, x, buf, Py_MIN(n, max_buf_size - 1));
20722096
break;
20732097
default:
20742098
PyErr_SetString(PyExc_TypeError, "instr requires 0 or 3 arguments");
2099+
goto error;
2100+
}
2101+
2102+
if (rtn == ERR) {
2103+
Py_DECREF(result);
2104+
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
2105+
}
2106+
2107+
if (_PyBytes_Resize(&result, strlen(buf)) < 0) {
20752108
return NULL;
20762109
}
2077-
if (rtn2 == ERR)
2078-
rtn[0] = 0;
2079-
return PyBytes_FromString(rtn);
2110+
2111+
return result;
2112+
2113+
error:
2114+
Py_DECREF(result);
2115+
return NULL;
20802116
}
20812117

20822118
/*[clinic input]

0 commit comments

Comments
 (0)
0