bpo-29734: nt._getfinalpathname handle leak (GH-740)
Make sure that failure paths call CloseHandle outside of the function that failed
(cherry picked from commit b82bfac436
)
Co-authored-by: Mark Becwar <mark@thebecwar.com>
This commit is contained in:
parent
04b2a5eeda
commit
63a69ef4a2
|
@ -2278,6 +2278,62 @@ class Win32JunctionTests(unittest.TestCase):
|
||||||
os.unlink(self.junction)
|
os.unlink(self.junction)
|
||||||
self.assertFalse(os.path.exists(self.junction))
|
self.assertFalse(os.path.exists(self.junction))
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
|
||||||
|
class Win32NtTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
from test import support
|
||||||
|
self.nt = support.import_module('nt')
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_getfinalpathname_handles(self):
|
||||||
|
try:
|
||||||
|
import ctypes, ctypes.wintypes
|
||||||
|
except ImportError:
|
||||||
|
raise unittest.SkipTest('ctypes module is required for this test')
|
||||||
|
|
||||||
|
kernel = ctypes.WinDLL('Kernel32.dll', use_last_error=True)
|
||||||
|
kernel.GetCurrentProcess.restype = ctypes.wintypes.HANDLE
|
||||||
|
|
||||||
|
kernel.GetProcessHandleCount.restype = ctypes.wintypes.BOOL
|
||||||
|
kernel.GetProcessHandleCount.argtypes = (ctypes.wintypes.HANDLE,
|
||||||
|
ctypes.wintypes.LPDWORD)
|
||||||
|
|
||||||
|
# This is a pseudo-handle that doesn't need to be closed
|
||||||
|
hproc = kernel.GetCurrentProcess()
|
||||||
|
|
||||||
|
handle_count = ctypes.wintypes.DWORD()
|
||||||
|
ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count))
|
||||||
|
self.assertEqual(1, ok)
|
||||||
|
|
||||||
|
before_count = handle_count.value
|
||||||
|
|
||||||
|
# The first two test the error path, __file__ tests the success path
|
||||||
|
filenames = [ r'\\?\C:',
|
||||||
|
r'\\?\NUL',
|
||||||
|
r'\\?\CONIN',
|
||||||
|
__file__ ]
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
for name in filenames:
|
||||||
|
try:
|
||||||
|
tmp = self.nt._getfinalpathname(name)
|
||||||
|
except:
|
||||||
|
# Failure is expected
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
tmp = os.stat(name)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
ok = kernel.GetProcessHandleCount(hproc, ctypes.byref(handle_count))
|
||||||
|
self.assertEqual(1, ok)
|
||||||
|
|
||||||
|
handle_delta = handle_count.value - before_count
|
||||||
|
|
||||||
|
self.assertEqual(0, handle_delta)
|
||||||
|
|
||||||
@support.skip_unless_symlink
|
@support.skip_unless_symlink
|
||||||
class NonLocalSymlinkTests(unittest.TestCase):
|
class NonLocalSymlinkTests(unittest.TestCase):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix handle leaks in os.stat on Windows.
|
|
@ -1616,11 +1616,6 @@ get_target_path(HANDLE hdl, wchar_t **target_path)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!CloseHandle(hdl)) {
|
|
||||||
PyMem_RawFree(buf);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[result_length] = 0;
|
buf[result_length] = 0;
|
||||||
|
|
||||||
*target_path = buf;
|
*target_path = buf;
|
||||||
|
@ -1678,9 +1673,10 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
if (!win32_get_reparse_tag(hFile, &reparse_tag))
|
if (!win32_get_reparse_tag(hFile, &reparse_tag)) {
|
||||||
|
CloseHandle(hFile);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
/* Close the outer open file handle now that we're about to
|
/* Close the outer open file handle now that we're about to
|
||||||
reopen it with different flags. */
|
reopen it with different flags. */
|
||||||
if (!CloseHandle(hFile))
|
if (!CloseHandle(hFile))
|
||||||
|
@ -1697,8 +1693,14 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
|
||||||
if (hFile2 == INVALID_HANDLE_VALUE)
|
if (hFile2 == INVALID_HANDLE_VALUE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!get_target_path(hFile2, &target_path))
|
if (!get_target_path(hFile2, &target_path)) {
|
||||||
|
CloseHandle(hFile2);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CloseHandle(hFile2)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
code = win32_xstat_impl(target_path, result, FALSE);
|
code = win32_xstat_impl(target_path, result, FALSE);
|
||||||
PyMem_RawFree(target_path);
|
PyMem_RawFree(target_path);
|
||||||
|
|
Loading…
Reference in New Issue