changeset: 89956:f2f0eec4a556 branch: 2.7 user: Victor Stinner date: Tue Mar 25 09:08:16 2014 +0100 files: Lib/tempfile.py Lib/test/test_tempfile.py Misc/NEWS description: Issue #21058: Fix a leak of file descriptor in tempfile.NamedTemporaryFile(), close the file descriptor if os.fdopen() fails diff -r 7ef262eafecd -r f2f0eec4a556 Lib/tempfile.py --- a/Lib/tempfile.py Mon Mar 24 19:49:42 2014 -0400 +++ b/Lib/tempfile.py Tue Mar 25 09:08:16 2014 +0100 @@ -460,8 +460,12 @@ flags |= _os.O_TEMPORARY (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - file = _os.fdopen(fd, mode, bufsize) - return _TemporaryFileWrapper(file, name, delete) + try: + file = _os.fdopen(fd, mode, bufsize) + return _TemporaryFileWrapper(file, name, delete) + except Exception: + _os.close(fd) + raise if _os.name != 'posix' or _os.sys.platform == 'cygwin': # On non-POSIX and Cygwin systems, assume that we cannot unlink a file diff -r 7ef262eafecd -r f2f0eec4a556 Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py Mon Mar 24 19:49:42 2014 -0400 +++ b/Lib/test/test_tempfile.py Tue Mar 25 09:08:16 2014 +0100 @@ -771,6 +771,24 @@ pass self.assertRaises(ValueError, use_closed) + def test_no_leak_fd(self): + # Issue #21058: don't leak file descriptor when fdopen() fails + old_close = os.close + old_fdopen = os.fdopen + closed = [] + def close(fd): + closed.append(fd) + def fdopen(*args): + raise ValueError() + os.close = close + os.fdopen = fdopen + try: + self.assertRaises(ValueError, tempfile.NamedTemporaryFile) + self.assertEqual(len(closed), 1) + finally: + os.close = old_close + os.fdopen = old_fdopen + # How to test the mode and bufsize parameters? test_classes.append(test_NamedTemporaryFile) diff -r 7ef262eafecd -r f2f0eec4a556 Misc/NEWS --- a/Misc/NEWS Mon Mar 24 19:49:42 2014 -0400 +++ b/Misc/NEWS Tue Mar 25 09:08:16 2014 +0100 @@ -40,6 +40,9 @@ Library ------- +- Issue #21058: Fix a leak of file descriptor in tempfile.NamedTemporaryFile(), + close the file descriptor if os.fdopen() fails + - Issue #20283: RE pattern methods now accept the string keyword parameters as documented. The pattern and source keyword parameters are left as deprecated aliases.