#define NDEBUG
#include <debug.h>
-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 */