Skip to content

Commit fd26e46

Browse files
petrutlucian94ader1990
authored andcommitted
Fix event listener crash
The MI operation cancel/close calls are asynchronuous for async subscriptions. The issue is that we're not waiting for those operations to complete when tearing down event watchers. For this reason, we may get event callbacks after deallocating those objects, which will lead to invalid memory access and crashes. This can be avoided by waiting for the MI operations to be canceled before going further with the teardown. After MI operations are canceled, a cancel notification is emitted and the "more_results" is set to False. We'll just wait for that.
1 parent 70f62fc commit fd26e46

File tree

1 file changed

+16
-0
lines changed

1 file changed

+16
-0
lines changed

PyMI/src/wmi/__init__.py

+16
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ def __init__(self, conn, wql):
434434
self._event = native_threading.Event()
435435
self._operation = conn.subscribe(
436436
wql, self._indication_result, self.close)
437+
self._operation_finished = native_threading.Event()
437438

438439
def _process_events(self):
439440
if self._error:
@@ -463,6 +464,9 @@ def __call__(self, timeout_ms=-1):
463464

464465
def _indication_result(self, instance, bookmark, machine_id, more_results,
465466
result_code, error_string, error_details):
467+
if not more_results:
468+
self._operation_finished.set()
469+
466470
if self._conn_ref:
467471
conn = self._conn_ref()
468472
if conn:
@@ -490,10 +494,22 @@ def _indication_result(self, instance, bookmark, machine_id, more_results,
490494
use_conn_weak_ref=True))
491495
self._event.set()
492496

497+
@avoid_blocking_call
498+
def _wait_for_operation_cancel(self):
499+
self._operation_finished.wait()
500+
493501
def close(self):
494502
if self._operation:
495503
self._operation.cancel()
504+
# Those operations are asynchronous. We'll need to wait for the
505+
# subscription to be canceled before deallocating objects,
506+
# otherwise MI can crash when receiving further events. We rely on
507+
# the fact that an event will be emitted once the subscription is
508+
# canceled.
509+
self._wait_for_operation_cancel()
510+
496511
self._operation.close()
512+
497513
self._event.set()
498514
self._operation = None
499515
self._timeout_ms = None

0 commit comments

Comments
 (0)