-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
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
NamedTemporaryFile could cause double-close on an fd if _TemporaryFileWrapper throws #83499
Comments
tempfile.NamedTemporaryFile creates its wrapper like so:
return _TemporaryFileWrapper(file, name, delete)
except BaseException:
_os.unlink(name)
_os.close(fd)
raise If _TemporaryFileWrapper throws any kind of exception (even KeyboardInterrupt), this closes This should probably be rewritten as:
or perhaps use nested try blocks to avoid the _os.unlink duplication. |
Instead of `except:` and `except BaseException:`, I think better use `except Exception:`. For further discussion and reference, also see the discussion here: https://news.ycombinator.com/item?id=22028581 |
This issue is more complex. I am working on it. |
Problems:
As for using I worked on this issue yesterday, but then found new problems, it will take several days or weeks to solve them. As a workaround I suggest to skip temporary the test which monkeypatches _TemporaryFileWrapper. |
Why is |
Could this be solvable if file = None
try:
file = io.open(fd, ..., closefd=False)
file.closefd = True
except:
if file and not file.closefd:
os.close(fd)
raise I believe this should be bulletproof - a KeyboardInterrupt can happen anywhere in the Of course, this can leak if a KeyboardInterrupt lands in the This is a somewhat annoying pattern, though. I wonder if there's a nicer way to implement it so we don't end up with this kind of boilerplate everywhere. |
If you anyway accept that KeyboardInterrupt can potentially leak, by just using |
I think it is worth pointing out that the semantics of
are broken (IMHO) because an exception can result in an unreferenced file Therefore it should be considered a bad idea to use open in this way. So I would suggest that NamedTemporaryFile's code should be:
And '_os.close(self.file.fileno())' should be added after each of the two calls Some notes on the design choices here.
|
I thought that if this raises a (normal) exception, it always means that it did not have overtaken the It this is not true right now, you are right that this is problematic. But this should be simple to fix on the CPython side, right? I.e. to make sure whenever some exception is raised here, even if some temporary file object already was constructed, it will not close |
The current CPython implementation does not guard against this happening. Some
I agree. I think it should be fairly simple to fix for CPython. |
Just a heads up in python 3.11 on Travis CI I am seeing a similar issue with sqlite throwing an I/O error https://app.travis-ci.com/github/roundup-tracker/roundup/jobs/573649310#L5779 So 3.11 might be more prone to this. Does it make sense to add 3.11 to the labels on this ticket. |
See #93874. It was mostly ready (except a NEWS entry and some polishing) more than 2 years ago. Now I do not remember why it was not finished at that time -- either I just put it off until the next morning, but was distracted by other issues and forgot about it, or I found some issues with it, or I found a better way. So please make a careful review. Maybe it was deferred because there is a very tiny possibility of a file descriptor leak if you interrupt the program between |
) (cherry picked from commit d4792ce) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
…onGH-93874) (cherry picked from commit d4792ce) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
) (cherry picked from commit d4792ce) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: