Skip to content

Commit

Permalink
pythongh-90102: Shortcut isatty in _io open()
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaloney committed Sep 10, 2024
1 parent 1a16077 commit be84f90
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 4 deletions.
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(_initializing)
STRUCT_FOR_ID(_io)
STRUCT_FOR_ID(_is_text_encoding)
STRUCT_FOR_ID(_isatty_openonly)
STRUCT_FOR_ID(_layout_)
STRUCT_FOR_ID(_length_)
STRUCT_FOR_ID(_limbo)
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,8 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode,

/* buffering */
if (buffering < 0) {
PyObject *res = PyObject_CallMethodNoArgs(raw, &_Py_ID(isatty));
PyObject *res = PyObject_CallMethodNoArgs(raw,
&_Py_ID(_isatty_openonly));
if (res == NULL)
goto error;
isatty = PyObject_IsTrue(res);
Expand Down
20 changes: 17 additions & 3 deletions Modules/_io/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
Expand Down Expand Up @@ -1207,6 +1204,22 @@ _io_FileIO_isatty_impl(fileio *self)
return PyBool_FromLong(res);
}

/* Checks whether the file is a TTY using an open-only optimization.
Normally isatty always makes a system call. In the case of open() there
is a _inside the same python call_ stat result which we can use to
skip that system call for non-character files. Outsid of that context
this is subject to TOCTOU issues (the FD has been returned to user code
and arbitrary syscalls could have happened). */
static PyObject *
_io_FileIO_isatty_openonly(fileio *self, void *Py_UNUSED(ignored))
{
if (self->stat_atopen != NULL && !S_ISCHR(self->stat_atopen->st_mode)) {
Py_RETURN_FALSE;
}
return _io_FileIO_isatty_impl(self);
}

#include "clinic/fileio.c.h"

static PyMethodDef fileio_methods[] = {
Expand All @@ -1223,6 +1236,7 @@ static PyMethodDef fileio_methods[] = {
_IO_FILEIO_WRITABLE_METHODDEF
_IO_FILEIO_FILENO_METHODDEF
_IO_FILEIO_ISATTY_METHODDEF
{"_isatty_openonly", (PyCFunction)_io_FileIO_isatty_openonly, METH_NOARGS},
{"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
{"__reduce__", _PyIOBase_cannot_pickle, METH_NOARGS},
{"__reduce_ex__", _PyIOBase_cannot_pickle, METH_O},
Expand Down

0 comments on commit be84f90

Please sign in to comment.