From 259f15f48a975a723b7cd3e26021266c8edddc3c Mon Sep 17 00:00:00 2001 From: Stefan Ginsberg Date: Thu, 17 Sep 2015 13:36:55 +0000 Subject: [PATCH 1/1] [RTL] Add support for vectored continue handlers, complementing the vectored exception handler support we already have, by doing some massive shared code usage: just use two different lists for the different handler types and all the code is basically the same. Call the "new" functionality from RtlDispatchException and stub it out for kernel mode. Clean up the existing code and simplify it. Passes the Winetests fine, not that they test this a a lot. #CORE-10202 svn path=/trunk/; revision=69259 --- reactos/dll/ntdll/ldr/ldrinit.c | 2 +- reactos/lib/rtl/i386/except.c | 15 +- reactos/lib/rtl/rtlp.h | 7 + reactos/lib/rtl/vectoreh.c | 425 +++++++++++++++++++++----------- reactos/ntoskrnl/rtl/libsupp.c | 14 +- 5 files changed, 306 insertions(+), 157 deletions(-) diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index 2bcfbebb85d..1d5468d5e9a 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -77,7 +77,7 @@ ULONG LdrpActiveUnloadCount; //extern LIST_ENTRY RtlCriticalSectionList; -VOID RtlpInitializeVectoredExceptionHandling(VOID); +VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID); VOID NTAPI RtlpInitDeferedCriticalSection(VOID); VOID NTAPI RtlInitializeHeapManager(VOID); extern BOOLEAN RtlpPageHeapEnabled; diff --git a/reactos/lib/rtl/i386/except.c b/reactos/lib/rtl/i386/except.c index ab465ebbbd9..20a77040fc5 100644 --- a/reactos/lib/rtl/i386/except.c +++ b/reactos/lib/rtl/i386/except.c @@ -74,10 +74,13 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, ULONG_PTR StackLow, StackHigh; ULONG_PTR RegistrationFrameEnd; - /* Perform vectored exception handling (a dummy in kernel mode) */ + /* Perform vectored exception handling for user mode */ if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context)) { - /* Exception handled, continue execution */ + /* Exception handled, now call vectored continue handlers */ + RtlCallVectoredContinueHandlers(ExceptionRecord, Context); + + /* Continue execution */ return TRUE; } @@ -139,7 +142,7 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, /* Handle the dispositions */ switch (Disposition) { - /* Continue searching */ + /* Continue execution */ case ExceptionContinueExecution: /* Check if it was non-continuable */ @@ -157,7 +160,11 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, } else { - /* Return to caller */ + /* In user mode, call any registered vectored continue handlers */ + RtlCallVectoredContinueHandlers(ExceptionRecord, + Context); + + /* Execution continues */ return TRUE; } diff --git a/reactos/lib/rtl/rtlp.h b/reactos/lib/rtl/rtlp.h index 47ae13576e4..96d395b1567 100644 --- a/reactos/lib/rtl/rtlp.h +++ b/reactos/lib/rtl/rtlp.h @@ -67,6 +67,13 @@ RtlCallVectoredExceptionHandlers( IN PCONTEXT Context ); +VOID +NTAPI +RtlCallVectoredContinueHandlers( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context +); + typedef struct _DISPATCHER_CONTEXT { PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; diff --git a/reactos/lib/rtl/vectoreh.c b/reactos/lib/rtl/vectoreh.c index ac3596c3b54..bac5754af68 100644 --- a/reactos/lib/rtl/vectoreh.c +++ b/reactos/lib/rtl/vectoreh.c @@ -13,201 +13,328 @@ #define NDEBUG #include -static RTL_CRITICAL_SECTION RtlpVectoredExceptionLock; -static LIST_ENTRY RtlpVectoredExceptionHead; -static volatile LONG RtlpVectoredExceptionsInstalled; +RTL_CRITICAL_SECTION RtlpVectoredHandlerLock; +LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList; -typedef struct _RTL_VECTORED_EXCEPTION_HANDLER +typedef struct _RTL_VECTORED_HANDLER_ENTRY { - LIST_ENTRY ListEntry; - PVECTORED_EXCEPTION_HANDLER VectoredHandler; - ULONG Refs; - BOOLEAN Deleted; -} RTL_VECTORED_EXCEPTION_HANDLER, *PRTL_VECTORED_EXCEPTION_HANDLER; + LIST_ENTRY ListEntry; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + ULONG Refs; +} RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY; /* FUNCTIONS ***************************************************************/ +VOID +NTAPI +RtlpInitializeVectoredExceptionHandling(VOID) +{ + /* Initialize our two lists and the common lock */ + RtlInitializeCriticalSection(&RtlpVectoredHandlerLock); + InitializeListHead(&RtlpVectoredExceptionList); + InitializeListHead(&RtlpVectoredContinueList); +} + BOOLEAN NTAPI -RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, - IN PCONTEXT Context) +RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN PLIST_ENTRY VectoredHandlerList) { - PLIST_ENTRY CurrentEntry; - PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; - PVECTORED_EXCEPTION_HANDLER VectoredHandler; - EXCEPTION_POINTERS ExceptionInfo; - BOOLEAN Remove = FALSE; - BOOLEAN Ret = FALSE; - - ExceptionInfo.ExceptionRecord = ExceptionRecord; - ExceptionInfo.ContextRecord = Context; - - if(RtlpVectoredExceptionsInstalled) - { - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - CurrentEntry = RtlpVectoredExceptionHead.Flink; - while (CurrentEntry != &RtlpVectoredExceptionHead) + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + EXCEPTION_POINTERS ExceptionInfo; + BOOLEAN HandlerRemoved; + LONG HandlerReturn; + + /* + * Initialize these in case there are no entries, + * or if no one handled the exception + */ + HandlerRemoved = FALSE; + HandlerReturn = EXCEPTION_CONTINUE_SEARCH; + + /* Set up the data to pass to the handler */ + ExceptionInfo.ExceptionRecord = ExceptionRecord; + ExceptionInfo.ContextRecord = Context; + + /* Grab the lock */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Loop entries */ + CurrentEntry = VectoredHandlerList->Flink; + while (CurrentEntry != VectoredHandlerList) { - veh = CONTAINING_RECORD(CurrentEntry, - RTL_VECTORED_EXCEPTION_HANDLER, - ListEntry); - veh->Refs++; - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - - VectoredHandler = RtlDecodePointer(veh->VectoredHandler); - if(VectoredHandler(&ExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION) - { - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - if (--veh->Refs == 0) + /* Get the struct */ + VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_HANDLER_ENTRY, + ListEntry); + + /* Reference it so it doesn't go away while we are using it */ + VectoredExceptionHandler->Refs++; + + /* Drop the lock before calling the handler */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* + * Get the function pointer, decoding it so we will crash + * if malicious code has altered it. That is, if something has + * set VectoredHandler to a non-encoded pointer + */ + VectoredHandler = RtlDecodePointer(VectoredExceptionHandler->VectoredHandler); + + /* Call the handler */ + HandlerReturn = VectoredHandler(&ExceptionInfo); + + /* Handler called -- grab the lock to dereference */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Dereference and see if it got deleted */ + VectoredExceptionHandler->Refs--; + if (VectoredExceptionHandler->Refs == 0) + { + /* It did -- do we have to free it now? */ + if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) + { + /* We don't, just remove it from the list and break out */ + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + HandlerRemoved = TRUE; + break; + } + + /* + * Get the next entry before freeing, + * and remove the current one from the list + */ + CurrentEntry = VectoredExceptionHandler->ListEntry.Flink; + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + + /* Free the entry outside of the lock, then reacquire it */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + RtlFreeHeap(RtlGetProcessHeap(), + 0, + VectoredExceptionHandler); + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + } + else { - RemoveEntryList (&veh->ListEntry); - InterlockedDecrement (&RtlpVectoredExceptionsInstalled); - Remove = TRUE; + /* No delete -- should we continue execution? */ + if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) + { + /* Break out */ + break; + } + else + { + /* Continue searching the list */ + CurrentEntry = CurrentEntry->Flink; + } } - Ret = TRUE; - break; - } - - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - - if (--veh->Refs == 0) - { - CurrentEntry = veh->ListEntry.Flink; - RemoveEntryList (&veh->ListEntry); - InterlockedDecrement (&RtlpVectoredExceptionsInstalled); - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - + } + + /* Let go of the lock now */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* Anything to free? */ + if (HandlerRemoved) + { + /* Get rid of it */ RtlFreeHeap(RtlGetProcessHeap(), 0, - veh); - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - } - else - CurrentEntry = CurrentEntry->Flink; + VectoredExceptionHandler); } - - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - } - - if (Remove) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - veh); - } - - return Ret; + + /* Return whether to continue execution (ignored for continue handlers) */ + return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE; } -VOID -RtlpInitializeVectoredExceptionHandling(VOID) +PVOID +NTAPI +RtlpAddVectoredHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler, + IN PLIST_ENTRY VectoredHandlerList) { - InitializeListHead(&RtlpVectoredExceptionHead); - RtlInitializeCriticalSection(&RtlpVectoredExceptionLock); - RtlpVectoredExceptionsInstalled = 0; -} + PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry; + /* Allocate our structure */ + VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(RTL_VECTORED_HANDLER_ENTRY)); + if (!VectoredHandlerEntry) return NULL; -/* - * @implemented - */ -PVOID NTAPI DECLSPEC_HOTPATCH -RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, - IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) -{ - PRTL_VECTORED_EXCEPTION_HANDLER veh; + /* Set it up, encoding the pointer for security */ + VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler); + VectoredHandlerEntry->Refs = 1; - veh = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(RTL_VECTORED_EXCEPTION_HANDLER)); - if(veh != NULL) - { - veh->VectoredHandler = RtlEncodePointer(VectoredHandler); - veh->Refs = 1; - veh->Deleted = FALSE; - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - if(FirstHandler != 0) + /* Lock the list before modifying it */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* + * While holding the list lock, insert the handler + * at beginning or end of list according to caller. + */ + if (FirstHandler) { - InsertHeadList(&RtlpVectoredExceptionHead, - &veh->ListEntry); + InsertHeadList(VectoredHandlerList, + &VectoredHandlerEntry->ListEntry); } else { - InsertTailList(&RtlpVectoredExceptionHead, - &veh->ListEntry); + InsertTailList(VectoredHandlerList, + &VectoredHandlerEntry->ListEntry); } - InterlockedIncrement (&RtlpVectoredExceptionsInstalled); - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - } - return veh; -} + /* Done with the list, unlock it */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + /* Return pointer to the structure as the handle */ + return VectoredHandlerEntry; +} -/* - * @implemented - */ -ULONG NTAPI -RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) +ULONG +NTAPI +RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle, + IN PLIST_ENTRY VectoredHandlerList) { - PLIST_ENTRY CurrentEntry; - PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; - BOOLEAN Remove = FALSE; - ULONG Ret = FALSE; - - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - for(CurrentEntry = RtlpVectoredExceptionHead.Flink; - CurrentEntry != &RtlpVectoredExceptionHead; - CurrentEntry = CurrentEntry->Flink) - { - veh = CONTAINING_RECORD(CurrentEntry, - RTL_VECTORED_EXCEPTION_HANDLER, - ListEntry); - if(veh == VectoredHandlerHandle) + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; + BOOLEAN HandlerRemoved; + BOOLEAN HandlerFound; + + /* Initialize these in case we don't find anything */ + HandlerRemoved = FALSE; + HandlerFound = FALSE; + + /* Acquire list lock */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Loop the list */ + CurrentEntry = VectoredHandlerList->Flink; + while (CurrentEntry != VectoredHandlerList) { - if (!veh->Deleted) - { - if (--veh->Refs == 0) + /* Get the struct */ + VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_HANDLER_ENTRY, + ListEntry); + + /* Does it match? */ + if (VectoredExceptionHandler == VectoredHandlerHandle) + { + /* + * Great, this means it is a valid entry. + * However, it may be in use by the exception + * dispatcher, so we have a ref count to respect. + * If we can't remove it now then it will be done + * right after it is not in use anymore. + * + * Caller is supposed to keep track of if it has deleted the + * entry and should not call us twice for the same entry. + * We could maybe throw in some kind of ASSERT to detect this + * if this was to become a problem. + */ + VectoredExceptionHandler->Refs--; + if (VectoredExceptionHandler->Refs == 0) + { + /* Not in use, ok to remove and free */ + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + HandlerRemoved = TRUE; + } + + /* Found what we are looking for, stop searching */ + HandlerFound = TRUE; + break; + } + else { - RemoveEntryList (&veh->ListEntry); - Remove = TRUE; + /* Get the next entry */ + CurrentEntry = CurrentEntry->Flink; } - veh->Deleted = TRUE; - Ret = TRUE; - break; - } } - } - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - if(Remove) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - veh); - } + /* Done with the list, let go of the lock */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* Can we free what we found? */ + if (HandlerRemoved) + { + /* Do it */ + RtlFreeHeap(RtlGetProcessHeap(), + 0, + VectoredExceptionHandler); + } + + /* Return whether we found it */ + return (ULONG)HandlerFound; +} + +BOOLEAN +NTAPI +RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + /* Call the shared routine */ + return RtlpCallVectoredHandlers(ExceptionRecord, + Context, + &RtlpVectoredExceptionList); +} - return Ret; +VOID +NTAPI +RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + /* + * Call the shared routine (ignoring result, + * execution always continues at this point) + */ + (VOID)RtlpCallVectoredHandlers(ExceptionRecord, + Context, + &RtlpVectoredContinueList); } +DECLSPEC_HOTPATCH PVOID NTAPI +RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +{ + /* Call the shared routine */ + return RtlpAddVectoredHandler(FirstHandler, + VectoredHandler, + &RtlpVectoredExceptionList); +} + DECLSPEC_HOTPATCH -RtlAddVectoredContinueHandler( - IN ULONG FirstHandler, - IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +PVOID +NTAPI +RtlAddVectoredContinueHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +{ + /* Call the shared routine */ + return RtlpAddVectoredHandler(FirstHandler, + VectoredHandler, + &RtlpVectoredContinueList); +} + +//DECLSPEC_HOTPATCH +ULONG +NTAPI +RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) { - UNIMPLEMENTED; - return NULL; + /* Call the shared routine */ + return RtlpRemoveVectoredHandler(VectoredHandlerHandle, + &RtlpVectoredExceptionList); } +//DECLSPEC_HOTPATCH ULONG NTAPI -RtlRemoveVectoredContinueHandler( - IN PVOID VectoredHandlerHandle) +RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle) { - UNIMPLEMENTED; - return FALSE; + /* Call the shared routine */ + return RtlpRemoveVectoredHandler(VectoredHandlerHandle, + &RtlpVectoredContinueList); } /* EOF */ diff --git a/reactos/ntoskrnl/rtl/libsupp.c b/reactos/ntoskrnl/rtl/libsupp.c index da6db038868..3eb6c97e8d1 100644 --- a/reactos/ntoskrnl/rtl/libsupp.c +++ b/reactos/ntoskrnl/rtl/libsupp.c @@ -764,12 +764,20 @@ RtlpSafeCopyMemory( BOOLEAN NTAPI -RtlCallVectoredExceptionHandlers( - _In_ PEXCEPTION_RECORD ExceptionRecord, - _In_ PCONTEXT Context) +RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT Context) { /* In the kernel we don't have vectored exception handlers */ return FALSE; } +VOID +NTAPI +RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT Context) +{ + /* No vectored continue handlers either in kernel mode */ + return; +} + /* EOF */ -- 2.17.1