* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS sysem libraries
* PURPOSE: Vectored Exception Handling
* FILE: lib/rtl/vectoreh.c
* PROGRAMERS: Thomas Weidenmueller
*/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
RTL_CRITICAL_SECTION RtlpVectoredHandlerLock;
LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList;
typedef struct _RTL_VECTORED_HANDLER_ENTRY
{
LIST_ENTRY ListEntry;
PVECTORED_EXCEPTION_HANDLER VectoredHandler;
ULONG Refs;
} RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY;
VOID
NTAPI
RtlpInitializeVectoredExceptionHandling(VOID)
{
RtlInitializeCriticalSection(&RtlpVectoredHandlerLock);
InitializeListHead(&RtlpVectoredExceptionList);
InitializeListHead(&RtlpVectoredContinueList);
}
BOOLEAN
NTAPI
RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT Context,
IN PLIST_ENTRY VectoredHandlerList)
{
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;
ExceptionInfo.ExceptionRecord = ExceptionRecord;
ExceptionInfo.ContextRecord = Context;
RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
CurrentEntry = VectoredHandlerList->Flink;
while (CurrentEntry != VectoredHandlerList)
{
VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry,
RTL_VECTORED_HANDLER_ENTRY,
ListEntry);
VectoredExceptionHandler->Refs++;
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);
HandlerReturn = VectoredHandler(&ExceptionInfo);
RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
VectoredExceptionHandler->Refs--;
if (VectoredExceptionHandler->Refs == 0)
{
if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION)
{
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);
RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
RtlFreeHeap(RtlGetProcessHeap(),
0,
VectoredExceptionHandler);
RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
}
else
{
if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION)
{
break;
}
else
{
CurrentEntry = CurrentEntry->Flink;
}
}
}
RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
if (HandlerRemoved)
{
RtlFreeHeap(RtlGetProcessHeap(),
0,
VectoredExceptionHandler);
}
return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE;
}
PVOID
NTAPI
RtlpAddVectoredHandler(IN ULONG FirstHandler,
IN PVECTORED_EXCEPTION_HANDLER VectoredHandler,
IN PLIST_ENTRY VectoredHandlerList)
{
PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry;
VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(),
0,
sizeof(RTL_VECTORED_HANDLER_ENTRY));
if (!VectoredHandlerEntry) return NULL;
VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler);
VectoredHandlerEntry->Refs = 1;
RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
* While holding the list lock, insert the handler
* at beginning or end of list according to caller.
*/
if (FirstHandler)
{
InsertHeadList(VectoredHandlerList,
&VectoredHandlerEntry->ListEntry);
}
else
{
InsertTailList(VectoredHandlerList,
&VectoredHandlerEntry->ListEntry);
}
RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
return VectoredHandlerEntry;
}
ULONG
NTAPI
RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle,
IN PLIST_ENTRY VectoredHandlerList)
{
PLIST_ENTRY CurrentEntry;
PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler;
BOOLEAN HandlerRemoved;
BOOLEAN HandlerFound;
HandlerRemoved = FALSE;
HandlerFound = FALSE;
RtlEnterCriticalSection(&RtlpVectoredHandlerLock);
CurrentEntry = VectoredHandlerList->Flink;
while (CurrentEntry != VectoredHandlerList)
{
VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry,
RTL_VECTORED_HANDLER_ENTRY,
ListEntry);
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)
{
RemoveEntryList(&VectoredExceptionHandler->ListEntry);
HandlerRemoved = TRUE;
}
HandlerFound = TRUE;
break;
}
else
{
CurrentEntry = CurrentEntry->Flink;
}
}
RtlLeaveCriticalSection(&RtlpVectoredHandlerLock);
if (HandlerRemoved)
{
RtlFreeHeap(RtlGetProcessHeap(),
0,
VectoredExceptionHandler);
}
return (ULONG)HandlerFound;
}
BOOLEAN
NTAPI
RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT Context)
{
return RtlpCallVectoredHandlers(ExceptionRecord,
Context,
&RtlpVectoredExceptionList);
}
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)
{
return RtlpAddVectoredHandler(FirstHandler,
VectoredHandler,
&RtlpVectoredExceptionList);
}
DECLSPEC_HOTPATCH
PVOID
NTAPI
RtlAddVectoredContinueHandler(IN ULONG FirstHandler,
IN PVECTORED_EXCEPTION_HANDLER VectoredHandler)
{
return RtlpAddVectoredHandler(FirstHandler,
VectoredHandler,
&RtlpVectoredContinueList);
}
ULONG
NTAPI
RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle)
{
return RtlpRemoveVectoredHandler(VectoredHandlerHandle,
&RtlpVectoredExceptionList);
}
ULONG
NTAPI
RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle)
{
return RtlpRemoveVectoredHandler(VectoredHandlerHandle,
&RtlpVectoredContinueList);
}