diff options
author | Mark Becwar <mark@thebecwar.com> | 2019-02-02 21:08:23 (GMT) |
---|---|---|
committer | Steve Dower <steve.dower@microsoft.com> | 2019-02-02 21:08:23 (GMT) |
commit | b82bfac4369c0429e562a834b3752e66c4821eab (patch) | |
tree | 24cb35ba11a8bd4e00d69b38081b85e17d4ebd31 /Lib/test/test_os.py | |
parent | cb0904762681031edc50f9d7d7ef48cffcf96d9a (diff) | |
download | cpython-b82bfac4369c0429e562a834b3752e66c4821eab.zip cpython-b82bfac4369c0429e562a834b3752e66c4821eab.tar.gz cpython-b82bfac4369c0429e562a834b3752e66c4821eab.tar.bz2 |
bpo-29734: nt._getfinalpathname handle leak (GH-740)
Make sure that failure paths call CloseHandle outside of the function that failed
Diffstat (limited to 'Lib/test/test_os.py')
-rw-r--r-- | Lib/test/test_os.py | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index aca445f..9e0bef5 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2325,6 +2325,62 @@ class Win32JunctionTests(unittest.TestCase): os.unlink(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 class NonLocalSymlinkTests(unittest.TestCase): |