mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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>
This commit is contained in:
parent
a3a3cf6d15
commit
aadda87b3d
3 changed files with 80 additions and 33 deletions
|
@ -988,6 +988,10 @@ the following methods and attributes:
|
||||||
window.getstr(y, x, n)
|
window.getstr(y, x, n)
|
||||||
|
|
||||||
Read a bytes object from the user, with primitive line editing capacity.
|
Read a bytes object from the user, with primitive line editing capacity.
|
||||||
|
The maximum value for *n* is 2047.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
The maximum value for *n* was increased from 1023 to 2047.
|
||||||
|
|
||||||
|
|
||||||
.. method:: window.getyx()
|
.. method:: window.getyx()
|
||||||
|
@ -1079,6 +1083,10 @@ the following methods and attributes:
|
||||||
current cursor position, or at *y*, *x* if specified. Attributes are stripped
|
current cursor position, or at *y*, *x* if specified. Attributes are stripped
|
||||||
from the characters. If *n* is specified, :meth:`instr` returns a string
|
from the characters. If *n* is specified, :meth:`instr` returns a string
|
||||||
at most *n* characters long (exclusive of the trailing NUL).
|
at most *n* characters long (exclusive of the trailing NUL).
|
||||||
|
The maximum value for *n* is 2047.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
The maximum value for *n* was increased from 1023 to 2047.
|
||||||
|
|
||||||
|
|
||||||
.. method:: window.is_linetouched(line)
|
.. method:: window.is_linetouched(line)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
:mod:`curses`: The :meth:`curses.window.instr` and :meth:`curses.window.getstr`
|
||||||
|
methods now allocate their internal buffer on the heap instead of the stack;
|
||||||
|
in addition, the max buffer size is increased from 1023 to 2047.
|
|
@ -1816,7 +1816,7 @@ _curses.window.getstr
|
||||||
x: int
|
x: int
|
||||||
X-coordinate.
|
X-coordinate.
|
||||||
]
|
]
|
||||||
n: int = 1023
|
n: int = 2047
|
||||||
Maximal number of characters.
|
Maximal number of characters.
|
||||||
/
|
/
|
||||||
|
|
||||||
|
@ -1829,62 +1829,80 @@ PyCursesWindow_GetStr(PyObject *op, PyObject *args)
|
||||||
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
|
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
|
||||||
|
|
||||||
int x, y, n;
|
int x, y, n;
|
||||||
char rtn[1024]; /* This should be big enough.. I hope */
|
int rtn;
|
||||||
int rtn2;
|
|
||||||
|
/* could make the buffer size larger/dynamic */
|
||||||
|
Py_ssize_t max_buf_size = 2048;
|
||||||
|
PyObject *result = PyBytes_FromStringAndSize(NULL, max_buf_size);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
char *buf = PyBytes_AS_STRING(result);
|
||||||
|
|
||||||
switch (PyTuple_Size(args)) {
|
switch (PyTuple_Size(args)) {
|
||||||
case 0:
|
case 0:
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rtn2 = wgetnstr(self->win,rtn, 1023);
|
rtn = wgetnstr(self->win, buf, max_buf_size - 1);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (!PyArg_ParseTuple(args,"i;n", &n))
|
if (!PyArg_ParseTuple(args,"i;n", &n))
|
||||||
return NULL;
|
goto error;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rtn2 = wgetnstr(self->win, rtn, Py_MIN(n, 1023));
|
rtn = wgetnstr(self->win, buf, Py_MIN(n, max_buf_size - 1));
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
|
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
|
||||||
return NULL;
|
goto error;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
#ifdef STRICT_SYSV_CURSES
|
#ifdef STRICT_SYSV_CURSES
|
||||||
rtn2 = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, 1023);
|
rtn = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, max_buf_size - 1);
|
||||||
#else
|
#else
|
||||||
rtn2 = mvwgetnstr(self->win,y,x,rtn, 1023);
|
rtn = mvwgetnstr(self->win,y,x,buf, max_buf_size - 1);
|
||||||
#endif
|
#endif
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n))
|
if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n))
|
||||||
return NULL;
|
goto error;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
#ifdef STRICT_SYSV_CURSES
|
#ifdef STRICT_SYSV_CURSES
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rtn2 = wmove(self->win,y,x)==ERR ? ERR :
|
rtn = wmove(self->win,y,x)==ERR ? ERR :
|
||||||
wgetnstr(self->win, rtn, Py_MIN(n, 1023));
|
wgetnstr(self->win, rtn, Py_MIN(n, max_buf_size - 1));
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
#else
|
#else
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rtn2 = mvwgetnstr(self->win, y, x, rtn, Py_MIN(n, 1023));
|
rtn = mvwgetnstr(self->win, y, x, buf, Py_MIN(n, max_buf_size - 1));
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_SetString(PyExc_TypeError, "getstr requires 0 to 3 arguments");
|
PyErr_SetString(PyExc_TypeError, "getstr requires 0 to 3 arguments");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtn == ERR) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_PyBytes_Resize(&result, strlen(buf)) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (rtn2 == ERR)
|
|
||||||
rtn[0] = 0;
|
return result;
|
||||||
return PyBytes_FromString(rtn);
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -2023,7 +2041,7 @@ _curses.window.instr
|
||||||
x: int
|
x: int
|
||||||
X-coordinate.
|
X-coordinate.
|
||||||
]
|
]
|
||||||
n: int = 1023
|
n: int = 2047
|
||||||
Maximal number of characters.
|
Maximal number of characters.
|
||||||
/
|
/
|
||||||
|
|
||||||
|
@ -2040,43 +2058,61 @@ PyCursesWindow_InStr(PyObject *op, PyObject *args)
|
||||||
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
|
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
|
||||||
|
|
||||||
int x, y, n;
|
int x, y, n;
|
||||||
char rtn[1024]; /* This should be big enough.. I hope */
|
int rtn;
|
||||||
int rtn2;
|
|
||||||
|
/* could make the buffer size larger/dynamic */
|
||||||
|
Py_ssize_t max_buf_size = 2048;
|
||||||
|
PyObject *result = PyBytes_FromStringAndSize(NULL, max_buf_size);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
char *buf = PyBytes_AS_STRING(result);
|
||||||
|
|
||||||
switch (PyTuple_Size(args)) {
|
switch (PyTuple_Size(args)) {
|
||||||
case 0:
|
case 0:
|
||||||
rtn2 = winnstr(self->win,rtn, 1023);
|
rtn = winnstr(self->win, buf, max_buf_size - 1);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (!PyArg_ParseTuple(args,"i;n", &n))
|
if (!PyArg_ParseTuple(args,"i;n", &n))
|
||||||
return NULL;
|
goto error;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
rtn2 = winnstr(self->win, rtn, Py_MIN(n, 1023));
|
rtn = winnstr(self->win, buf, Py_MIN(n, max_buf_size - 1));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
|
if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x))
|
||||||
return NULL;
|
goto error;
|
||||||
rtn2 = mvwinnstr(self->win,y,x,rtn,1023);
|
rtn = mvwinnstr(self->win, y, x, buf, max_buf_size - 1);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n))
|
if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n))
|
||||||
return NULL;
|
goto error;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative");
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
rtn2 = mvwinnstr(self->win, y, x, rtn, Py_MIN(n,1023));
|
rtn = mvwinnstr(self->win, y, x, buf, Py_MIN(n, max_buf_size - 1));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_SetString(PyExc_TypeError, "instr requires 0 or 3 arguments");
|
PyErr_SetString(PyExc_TypeError, "instr requires 0 or 3 arguments");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtn == ERR) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_PyBytes_Resize(&result, strlen(buf)) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (rtn2 == ERR)
|
|
||||||
rtn[0] = 0;
|
return result;
|
||||||
return PyBytes_FromString(rtn);
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue