Repository navigation
gh-120754: Ensure _stat_atopen is cleared on fd change #125166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
d57abd0
d2cb365
854ae91
c6da86e
0f64483
e2eebb0
5299a04
d749709
b429587
f08defa
e153d97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,7 +115,7 @@ fileio_dealloc_warn(PyObject *op, PyObject *source) | |
|
|
||
| /* Returns 0 on success, -1 with exception set on failure. */ | ||
| static int | ||
| internal_close(fileio *self) | ||
| internal_close(fileio *self, bool clear_stat) | ||
| { | ||
| int err = 0; | ||
| int save_errno = 0; | ||
|
|
@@ -130,6 +130,11 @@ internal_close(fileio *self) | |
| save_errno = errno; | ||
| _Py_END_SUPPRESS_IPH | ||
| Py_END_ALLOW_THREADS | ||
|
|
||
| } | ||
| if (clear_stat && self->stat_atopen != NULL) { | ||
| PyMem_Free(self->stat_atopen); | ||
| self->stat_atopen = NULL; | ||
| } | ||
| if (err < 0) { | ||
| errno = save_errno; | ||
|
|
@@ -178,7 +183,7 @@ _io_FileIO_close_impl(fileio *self, PyTypeObject *cls) | |
| PyErr_Clear(); | ||
| } | ||
| } | ||
| rc = internal_close(self); | ||
| rc = internal_close(self, true); | ||
| if (res == NULL) { | ||
| _PyErr_ChainExceptions1(exc); | ||
| } | ||
|
|
@@ -267,9 +272,12 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, | |
| #endif | ||
| if (self->fd >= 0) { | ||
| if (self->closefd) { | ||
| /* Have to close the existing file first. */ | ||
| if (internal_close(self) < 0) | ||
| /* Have to close the existing file first. | ||
|
|
||
| This leaves the stat so we can reuse the memory. */ | ||
| if (internal_close(self, false) < 0) { | ||
| return -1; | ||
| } | ||
| } | ||
| else | ||
| self->fd = -1; | ||
|
|
@@ -455,12 +463,15 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, | |
| #endif | ||
| } | ||
|
|
||
| PyMem_Free(self->stat_atopen); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure which is preferred here. The Free + New back to back feels weird, but version with the conditional feels like "extra work/code that should never be executed" (but that the compiler / tools that run currently won't validate...).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to that, dropped comment and simplified / back to always calling PyMem_New |
||
| self->stat_atopen = PyMem_New(struct _Py_stat_struct, 1); | ||
| /* Reuse stat_atopen memory if possible. */ | ||
| if (self->stat_atopen == NULL) { | ||
| PyErr_NoMemory(); | ||
| goto error; | ||
| self->stat_atopen = PyMem_New(struct _Py_stat_struct, 1); | ||
| if (self->stat_atopen == NULL) { | ||
| PyErr_NoMemory(); | ||
| goto error; | ||
| } | ||
| } | ||
|
|
||
| Py_BEGIN_ALLOW_THREADS | ||
| fstat_result = _Py_fstat_noraise(self->fd, self->stat_atopen); | ||
| Py_END_ALLOW_THREADS | ||
|
|
@@ -520,7 +531,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, | |
| self->fd = -1; | ||
| if (self->fd >= 0) { | ||
| PyObject *exc = PyErr_GetRaisedException(); | ||
| internal_close(self); | ||
| internal_close(self, true); | ||
| _PyErr_ChainExceptions1(exc); | ||
| } | ||
| if (self->stat_atopen != NULL) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this optimization is worth it, I would prefer to always clear the cache in close().