mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Fix some handle leak, debugger close hFile on event + enumerate processes/threads close snap handle
This commit is contained in:
@@ -674,8 +674,10 @@ class Debugger(object):
|
||||
self._setup_pending_breakpoints_new_process(self.current_process)
|
||||
self._setup_pending_breakpoints_new_thread(self.current_thread)
|
||||
with self.DisabledMemoryBreakpoint():
|
||||
return self.on_create_process(create_process)
|
||||
# TODO: close hFile
|
||||
try:
|
||||
return self.on_create_process(create_process)
|
||||
finally:
|
||||
winproxy.CloseHandle(create_process.hFile)
|
||||
|
||||
def _handle_exit_process(self, debug_event):
|
||||
"""Handle EXIT_PROCESS_DEBUG_EVENT"""
|
||||
@@ -745,7 +747,10 @@ class Debugger(object):
|
||||
self._module_by_process[self.current_process.pid][dll_name] = windows.pe_parse.GetPEFile(load_dll.lpBaseOfDll, self.current_process)
|
||||
self._setup_pending_breakpoints_load_dll(dll_name)
|
||||
with self.DisabledMemoryBreakpoint():
|
||||
return self.on_load_dll(load_dll)
|
||||
try:
|
||||
return self.on_load_dll(load_dll)
|
||||
finally:
|
||||
winproxy.CloseHandle(load_dll.hFile)
|
||||
|
||||
def _handle_unload_dll(self, debug_event):
|
||||
"""Handle UNLOAD_DLL_DEBUG_EVENT"""
|
||||
|
||||
@@ -17,8 +17,8 @@ class SystemTestCase(unittest.TestCase):
|
||||
|
||||
@check_for_gc_garbage
|
||||
def test_version_name(self):
|
||||
|
||||
return windows.system.version_name
|
||||
|
||||
@check_for_gc_garbage
|
||||
def test_computer_name(self):
|
||||
return windows.system.computer_name
|
||||
@@ -32,10 +32,7 @@ class SystemTestCase(unittest.TestCase):
|
||||
return windows.system.logicaldrives
|
||||
|
||||
@check_for_gc_garbage
|
||||
def test_processes(self):
|
||||
return windows.system.processes
|
||||
|
||||
@check_for_gc_garbage
|
||||
@check_for_handle_leak
|
||||
def test_threads(self):
|
||||
return windows.system.threads
|
||||
|
||||
@@ -44,6 +41,7 @@ class SystemTestCase(unittest.TestCase):
|
||||
return windows.system.wmi.select("Win32_Process", "*")
|
||||
|
||||
@check_for_gc_garbage
|
||||
@check_for_handle_leak
|
||||
def test_processes(self):
|
||||
procs = windows.system.processes
|
||||
self.assertIn(windows.current_process.pid, [p.pid for p in procs])
|
||||
|
||||
@@ -88,11 +88,45 @@ def check_for_gc_garbage(f):
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
def check_for_handle_leak(f):
|
||||
def wrapper(testcase, *args, **kwargs):
|
||||
current_process_hdebugger.refresh_handles()
|
||||
res = f(testcase, *args, **kwargs)
|
||||
leaked_handles = current_process_hdebugger.get_new_handle()
|
||||
testcase.assertFalse(leaked_handles, "Test Leaked <{0}> handles of types ({1})".format(len(leaked_handles), set(h.type for h in leaked_handles)))
|
||||
return res
|
||||
return wrapper
|
||||
|
||||
def print_call(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
res = f(*args, **kwargs)
|
||||
print("Call to <{0}>({1}) returned <{2}>".format(f.func_name, (args, kwargs), res))
|
||||
return res
|
||||
return wrapper
|
||||
return wrapper
|
||||
|
||||
|
||||
class HandleDebugger(object):
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self.handles = 0
|
||||
|
||||
def refresh_handles(self):
|
||||
self.handles = self.get_handles()
|
||||
|
||||
def get_handles(self):
|
||||
tpid = self.pid
|
||||
return [h for h in windows.system.handles if h.dwProcessId == tpid]
|
||||
|
||||
def get_new_handle(self):
|
||||
nh = self.get_handles()
|
||||
handle_diff = set(h.wValue for h in nh) - set(h.wValue for h in self.handles)
|
||||
return [h for h in nh if h.wValue in handle_diff]
|
||||
|
||||
def handles_types(self, hlist):
|
||||
return set(h.type for h in hlist)
|
||||
|
||||
def print_new_handle_type(self):
|
||||
print(self.handles_types(self.get_new_handle()))
|
||||
|
||||
|
||||
current_process_hdebugger = HandleDebugger(windows.current_process.pid)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import ctypes
|
||||
|
||||
import windows
|
||||
@@ -9,6 +10,7 @@ from windows.generated_def.winstructs import *
|
||||
class EPUBLIC_OBJECT_TYPE_INFORMATION(ctypes.Structure):
|
||||
_fields_ = windows.utils.transform_ctypes_fields(PUBLIC_OBJECT_TYPE_INFORMATION, {"TypeName": windows.winobject.process.WinUnicodeString})
|
||||
|
||||
current_process_pid = os.getpid()
|
||||
|
||||
class Handle(SYSTEM_HANDLE):
|
||||
"""A handle of the system"""
|
||||
@@ -86,7 +88,7 @@ class Handle(SYSTEM_HANDLE):
|
||||
return "<{0} value=<0x{1:x}> in process pid={2}>".format(type(self).__name__, self.wValue, self.dwProcessId)
|
||||
|
||||
def __del__(self):
|
||||
if self.dwProcessId == windows.current_process.pid:
|
||||
if self.dwProcessId == current_process_pid:
|
||||
return
|
||||
if hasattr(self, "_local_handle"):
|
||||
return winproxy.CloseHandle(self._local_handle)
|
||||
|
||||
@@ -210,6 +210,7 @@ class System(object):
|
||||
res.append(process.WinProcess._from_PROCESSENTRY32(process_entry))
|
||||
while winproxy.Process32Next(snap, process_entry):
|
||||
res.append(process.WinProcess._from_PROCESSENTRY32(process_entry))
|
||||
winproxy.CloseHandle(snap)
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
@@ -222,4 +223,5 @@ class System(object):
|
||||
threads.append(copy.copy(thread_entry))
|
||||
while winproxy.Thread32Next(snap, thread_entry):
|
||||
threads.append(copy.copy(thread_entry))
|
||||
return threads
|
||||
winproxy.CloseHandle(snap)
|
||||
return threads
|
||||
|
||||
Reference in New Issue
Block a user