diff --git a/Misc/NEWS b/Misc/NEWS index eb870b7d48b76b..83c654c3e4da14 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -227,6 +227,10 @@ Extension Modules Library ------- +- bpo-29176: getwin() and putwin() functions of the curses module now use + :class:`tempfile.TemporaryFile` instead of calling the C ``mkstemp()`` + function to create a temporary file in a more portable and safer manner. + - Issue #29100: Fix datetime.fromtimestamp() regression introduced in Python 3.6.0: check minimum and maximum years. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index e6a2f25121ed32..d831a51f06b8c8 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1715,30 +1715,91 @@ PyCursesWindow_Overwrite(PyCursesWindowObject *self, PyObject *args) } } +static void +close_temporary_file(PyObject *tmpfile) +{ + PyObject *exc, *val, *tb, *res; + + PyErr_Fetch(&exc, &val, &tb); + + res = PyObject_CallMethod(tmpfile, "close", NULL); + if (res) { + Py_DECREF(res); + } + else { + PyErr_WriteUnraisable(tmpfile); + } + + PyErr_Restore(exc, val, tb); +} + +static PyObject* +temporary_file(FILE **fp) +{ + PyObject *module, *tmpfile, *fileno; + int fd, fd2; + + module = PyImport_ImportModuleNoBlock("tempfile"); + if (module == NULL) { + return NULL; + } + + tmpfile = PyObject_CallMethod(module, "TemporaryFile", NULL); + Py_DECREF(module); + if (tmpfile == NULL) { + return NULL; + } + + fileno = PyObject_CallMethod(tmpfile, "fileno", NULL); + if (fileno == NULL) { + goto error; + } + fd = _PyLong_AsInt(fileno); + Py_DECREF(fileno); + if (fd < 0 && PyErr_Occurred()) { + goto error; + } + + /* Duplicate the file descriptor to be able call tmpfile.close() + and fclose(fp). curses requires a FILE* object, whereas Python requires + to call the close() method to remove the temporary file. */ + fd2 = _Py_dup(fd); + if (fd2 < 0) { + goto error; + } + + *fp = fdopen(fd2, "wb+"); + if (*fp == NULL) { + close(fd2); + goto error; + } + return tmpfile; + +error: + close_temporary_file(tmpfile); + Py_DECREF(tmpfile); + return NULL; +} + static PyObject * PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *stream) { /* We have to simulate this by writing to a temporary FILE*, then reading back, then writing to the argument stream. */ - char fn[100]; - int fd = -1; - FILE *fp = NULL; + PyObject *tmpfile; + FILE *fp; PyObject *res = NULL; - strcpy(fn, "/tmp/py.curses.putwin.XXXXXX"); - fd = mkstemp(fn); - if (fd < 0) - return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); - if (_Py_set_inheritable(fd, 0, NULL) < 0) - goto exit; - fp = fdopen(fd, "wb+"); - if (fp == NULL) { - PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); - goto exit; + tmpfile = temporary_file(&fp); + if (tmpfile == NULL) { + return NULL; } + res = PyCursesCheckERR(putwin(self->win, fp), "putwin"); - if (res == NULL) + if (res == NULL) { goto exit; + } + fseek(fp, 0, 0); while (1) { char buf[BUFSIZ]; @@ -1754,11 +1815,13 @@ PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *stream) } exit: - if (fp != NULL) + if (fp) { fclose(fp); - else if (fd != -1) - close(fd); - remove(fn); + } + if (tmpfile) { + close_temporary_file(tmpfile); + Py_DECREF(tmpfile); + } return res; } @@ -2278,9 +2341,8 @@ PyCurses_UngetMouse(PyObject *self, PyObject *args) static PyObject * PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) { - char fn[100]; - int fd = -1; - FILE *fp = NULL; + PyObject *tmpfile; + FILE *fp; PyObject *data; size_t datalen; WINDOW *win; @@ -2289,16 +2351,9 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) PyCursesInitialised; - strcpy(fn, "/tmp/py.curses.getwin.XXXXXX"); - fd = mkstemp(fn); - if (fd < 0) - return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); - if (_Py_set_inheritable(fd, 0, NULL) < 0) - goto error; - fp = fdopen(fd, "wb+"); - if (fp == NULL) { - PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); - goto error; + tmpfile = temporary_file(&fp); + if (tmpfile == NULL) { + return NULL; } data = _PyObject_CallMethodId(stream, &PyId_read, NULL); @@ -2314,7 +2369,7 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) datalen = PyBytes_GET_SIZE(data); if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) { Py_DECREF(data); - PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); + PyErr_SetFromErrno(PyExc_OSError); goto error; } Py_DECREF(data); @@ -2328,11 +2383,13 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) res = PyCursesWindow_New(win, NULL); error: - if (fp != NULL) + if (fp) { fclose(fp); - else if (fd != -1) - close(fd); - remove(fn); + } + if (tmpfile) { + close_temporary_file(tmpfile); + Py_DECREF(tmpfile); + } return res; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy