From 72dd4714f944e5927656aa25f5cd9bdcd3b00a76 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Fri, 1 Nov 2024 14:50:49 -0700 Subject: [PATCH] gh-120754: _io Ensure stat cache is cleared on fd change (#125166) Performed an audit of `fileio.c` and `_pyio` and made sure anytime the fd changes the stat result, if set, is also cleared/changed. There's one case where it's not cleared, if code would clear it in __init__, keep the memory allocated and just do another fstat with the existing memory. --- Lib/_pyio.py | 3 +++ Modules/_io/fileio.c | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 7b6d10c008d..42b0aea4e2e 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -1480,6 +1480,7 @@ class FileIO(RawIOBase): """ if self._fd >= 0: # Have to close the existing file first. + self._stat_atopen = None try: if self._closefd: os.close(self._fd) @@ -1583,6 +1584,7 @@ class FileIO(RawIOBase): if e.errno != errno.ESPIPE: raise except: + self._stat_atopen = None if owned_fd is not None: os.close(owned_fd) raise @@ -1756,6 +1758,7 @@ class FileIO(RawIOBase): called more than once without error. """ if not self.closed: + self._stat_atopen = None try: if self._closefd: os.close(self._fd) diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index f374592eb95..cf0f1d671b5 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -131,6 +131,8 @@ internal_close(fileio *self) _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } + PyMem_Free(self->stat_atopen); + self->stat_atopen = NULL; if (err < 0) { errno = save_errno; PyErr_SetFromErrno(PyExc_OSError); @@ -268,8 +270,9 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, if (self->fd >= 0) { if (self->closefd) { /* Have to close the existing file first. */ - if (internal_close(self) < 0) + if (internal_close(self) < 0) { return -1; + } } else self->fd = -1; @@ -523,10 +526,8 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, internal_close(self); _PyErr_ChainExceptions1(exc); } - if (self->stat_atopen != NULL) { - PyMem_Free(self->stat_atopen); - self->stat_atopen = NULL; - } + PyMem_Free(self->stat_atopen); + self->stat_atopen = NULL; done: #ifdef MS_WINDOWS