diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 63fd281b4b5..33868c76911 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -44,6 +44,7 @@ typedef struct { struct list entry; PVECTORED_EXCEPTION_HANDLER func; + ULONG count; } VECTORED_HANDLER; static struct list vectored_handlers = LIST_INIT(vectored_handlers); @@ -158,21 +159,37 @@ LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) struct list *ptr; LONG ret = EXCEPTION_CONTINUE_SEARCH; EXCEPTION_POINTERS except_ptrs; + VECTORED_HANDLER *handler, *to_free = NULL; except_ptrs.ExceptionRecord = rec; except_ptrs.ContextRecord = context; RtlEnterCriticalSection( &vectored_handlers_section ); - LIST_FOR_EACH( ptr, &vectored_handlers ) + ptr = list_head( &vectored_handlers ); + while (ptr) { - VECTORED_HANDLER *handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry ); + handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry ); + handler->count++; + RtlLeaveCriticalSection( &vectored_handlers_section ); + RtlFreeHeap( GetProcessHeap(), 0, to_free ); + to_free = NULL; + TRACE( "calling handler at %p code=%x flags=%x\n", handler->func, rec->ExceptionCode, rec->ExceptionFlags ); ret = handler->func( &except_ptrs ); TRACE( "handler at %p returned %x\n", handler->func, ret ); + + RtlEnterCriticalSection( &vectored_handlers_section ); + ptr = list_next( &vectored_handlers, ptr ); + if (!--handler->count) /* removed during execution */ + { + list_remove( &handler->entry ); + to_free = handler; + } if (ret == EXCEPTION_CONTINUE_EXECUTION) break; } RtlLeaveCriticalSection( &vectored_handlers_section ); + RtlFreeHeap( GetProcessHeap(), 0, to_free ); return ret; } @@ -214,6 +231,7 @@ PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HA if (handler) { handler->func = func; + handler->count = 1; RtlEnterCriticalSection( &vectored_handlers_section ); if (first) list_add_head( &vectored_handlers, &handler->entry ); else list_add_tail( &vectored_handlers, &handler->entry ); @@ -237,7 +255,8 @@ ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler ) VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry ); if (curr_handler == handler) { - list_remove( ptr ); + if (!--curr_handler->count) list_remove( ptr ); + else handler = NULL; /* don't free it yet */ ret = TRUE; break; }