mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 07:42:59 +00:00
- Fix some insidious bugs in exception handling, mostly related to the art of unwinding (RtlUnwind).
- Can't name specifics, but probably fixes multiple SEH/application bugs/regressions since about 6-8 months ago. Fixes my personal SEH test from 22 failures/crashes/BSODs to 22 succeesses... - Also fixes some crashes in kernel-kqemu mode. svn path=/trunk/; revision=24178
This commit is contained in:
parent
45f71f78c8
commit
3e709fbbd9
3 changed files with 107 additions and 98 deletions
|
@ -26,14 +26,12 @@ RtlRaiseException(PEXCEPTION_RECORD ExceptionRecord)
|
||||||
{
|
{
|
||||||
CONTEXT Context;
|
CONTEXT Context;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
DPRINT1("RtlRaiseException(Status %p)\n", ExceptionRecord);
|
|
||||||
|
|
||||||
/* Capture the context */
|
/* Capture the context */
|
||||||
RtlCaptureContext(&Context);
|
RtlCaptureContext(&Context);
|
||||||
|
|
||||||
/* Save the exception address */
|
/* Save the exception address */
|
||||||
ExceptionRecord->ExceptionAddress = RtlpGetExceptionAddress();
|
ExceptionRecord->ExceptionAddress = RtlpGetExceptionAddress();
|
||||||
DPRINT1("ExceptionAddress %p\n", ExceptionRecord->ExceptionAddress);
|
|
||||||
|
|
||||||
/* Write the context flag */
|
/* Write the context flag */
|
||||||
Context.ContextFlags = CONTEXT_FULL;
|
Context.ContextFlags = CONTEXT_FULL;
|
||||||
|
@ -72,7 +70,6 @@ RtlRaiseStatus(NTSTATUS Status)
|
||||||
{
|
{
|
||||||
EXCEPTION_RECORD ExceptionRecord;
|
EXCEPTION_RECORD ExceptionRecord;
|
||||||
CONTEXT Context;
|
CONTEXT Context;
|
||||||
DPRINT1("RtlRaiseStatus(Status 0x%.08lx)\n", Status);
|
|
||||||
|
|
||||||
/* Capture the context */
|
/* Capture the context */
|
||||||
RtlCaptureContext(&Context);
|
RtlCaptureContext(&Context);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
_RtlpGetExceptionList@0:
|
_RtlpGetExceptionList@0:
|
||||||
|
|
||||||
/* Return the exception list */
|
/* Return the exception list */
|
||||||
mov eax, [fs:TEB_EXCEPTION_LIST]
|
mov eax, fs:[TEB_EXCEPTION_LIST]
|
||||||
ret
|
ret
|
||||||
.endfunc
|
.endfunc
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ _RtlpSetExceptionList@4:
|
||||||
mov ecx, [ecx]
|
mov ecx, [ecx]
|
||||||
|
|
||||||
/* Write it */
|
/* Write it */
|
||||||
mov [fs:TEB_EXCEPTION_LIST], ecx
|
mov fs:[TEB_EXCEPTION_LIST], ecx
|
||||||
|
|
||||||
/* Return */
|
/* Return */
|
||||||
ret 4
|
ret 4
|
||||||
|
|
|
@ -29,6 +29,11 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList);
|
RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList);
|
||||||
|
|
||||||
|
typedef struct _DISPATCHER_CONTEXT
|
||||||
|
{
|
||||||
|
PEXCEPTION_REGISTRATION_RECORD RegistrationPointer;
|
||||||
|
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS **********************************************************/
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -51,9 +56,9 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
IN PCONTEXT Context)
|
IN PCONTEXT Context)
|
||||||
{
|
{
|
||||||
PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL;
|
PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL;
|
||||||
PEXCEPTION_REGISTRATION_RECORD DispatcherContext;
|
DISPATCHER_CONTEXT DispatcherContext;
|
||||||
EXCEPTION_RECORD ExceptionRecord2;
|
EXCEPTION_RECORD ExceptionRecord2;
|
||||||
EXCEPTION_DISPOSITION ReturnValue;
|
EXCEPTION_DISPOSITION Disposition;
|
||||||
ULONG_PTR StackLow, StackHigh;
|
ULONG_PTR StackLow, StackHigh;
|
||||||
ULONG_PTR RegistrationFrameEnd;
|
ULONG_PTR RegistrationFrameEnd;
|
||||||
|
|
||||||
|
@ -85,9 +90,6 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
|
|
||||||
/* Set invalid stack and return false */
|
/* Set invalid stack and return false */
|
||||||
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
|
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
|
||||||
DPRINT1("Invalid exception frame: %p %p %p %p\n",
|
|
||||||
RegistrationFrame, RegistrationFrameEnd,
|
|
||||||
StackHigh, StackLow);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,11 +100,12 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
sizeof(*RegistrationFrame));
|
sizeof(*RegistrationFrame));
|
||||||
|
|
||||||
/* Call the handler */
|
/* Call the handler */
|
||||||
ReturnValue = RtlpExecuteHandlerForException(ExceptionRecord,
|
Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
|
||||||
RegistrationFrame,
|
RegistrationFrame,
|
||||||
Context,
|
Context,
|
||||||
&DispatcherContext,
|
&DispatcherContext,
|
||||||
RegistrationFrame->Handler);
|
RegistrationFrame->
|
||||||
|
Handler);
|
||||||
|
|
||||||
/* Check if this is a nested frame */
|
/* Check if this is a nested frame */
|
||||||
if (RegistrationFrame == NestedFrame)
|
if (RegistrationFrame == NestedFrame)
|
||||||
|
@ -113,14 +116,18 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the dispositions */
|
/* Handle the dispositions */
|
||||||
if (ReturnValue == ExceptionContinueExecution)
|
switch (Disposition)
|
||||||
{
|
{
|
||||||
|
/* Continue searching */
|
||||||
|
case ExceptionContinueExecution:
|
||||||
|
|
||||||
/* Check if it was non-continuable */
|
/* Check if it was non-continuable */
|
||||||
if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
|
if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
|
||||||
{
|
{
|
||||||
/* Set up the exception record */
|
/* Set up the exception record */
|
||||||
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
||||||
ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
|
ExceptionRecord2.ExceptionCode =
|
||||||
|
STATUS_NONCONTINUABLE_EXCEPTION;
|
||||||
ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||||
ExceptionRecord2.NumberParameters = 0;
|
ExceptionRecord2.NumberParameters = 0;
|
||||||
|
|
||||||
|
@ -132,21 +139,28 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
/* Return to caller */
|
/* Return to caller */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (ReturnValue == ExceptionNestedException)
|
/* Continue searching */
|
||||||
{
|
case ExceptionContinueSearch:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Nested exception */
|
||||||
|
case ExceptionNestedException:
|
||||||
|
|
||||||
/* Turn the nested flag on */
|
/* Turn the nested flag on */
|
||||||
ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
|
ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
|
||||||
|
|
||||||
/* Update the current nested frame */
|
/* Update the current nested frame */
|
||||||
if (NestedFrame < DispatcherContext) NestedFrame = DispatcherContext;
|
if (DispatcherContext.RegistrationPointer > NestedFrame)
|
||||||
}
|
|
||||||
else if (ReturnValue == ExceptionContinueSearch)
|
|
||||||
{
|
{
|
||||||
/* Do nothing */
|
/* Get the frame from the dispatcher context */
|
||||||
|
NestedFrame = DispatcherContext.RegistrationPointer;
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
{
|
|
||||||
|
/* Anything else */
|
||||||
|
default:
|
||||||
|
|
||||||
/* Set up the exception record */
|
/* Set up the exception record */
|
||||||
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
||||||
ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
|
ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
|
||||||
|
@ -155,6 +169,7 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
|
|
||||||
/* Raise the exception */
|
/* Raise the exception */
|
||||||
RtlRaiseException(&ExceptionRecord2);
|
RtlRaiseException(&ExceptionRecord2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to the next frame */
|
/* Go to the next frame */
|
||||||
|
@ -170,15 +185,15 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
*/
|
*/
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
RtlUnwind(IN PVOID TargetFrame OPTIONAL,
|
||||||
PVOID ReturnAddress OPTIONAL,
|
IN PVOID TargetIp OPTIONAL,
|
||||||
PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
|
IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
|
||||||
PVOID EaxValue)
|
IN PVOID ReturnValue)
|
||||||
{
|
{
|
||||||
PEXCEPTION_REGISTRATION_RECORD RegistrationFrame2, OldFrame;
|
PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame;
|
||||||
PEXCEPTION_REGISTRATION_RECORD DispatcherContext;
|
DISPATCHER_CONTEXT DispatcherContext;
|
||||||
EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3;
|
EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3;
|
||||||
EXCEPTION_DISPOSITION ReturnValue;
|
EXCEPTION_DISPOSITION Disposition;
|
||||||
ULONG_PTR StackLow, StackHigh;
|
ULONG_PTR StackLow, StackHigh;
|
||||||
ULONG_PTR RegistrationFrameEnd;
|
ULONG_PTR RegistrationFrameEnd;
|
||||||
CONTEXT LocalContext;
|
CONTEXT LocalContext;
|
||||||
|
@ -202,7 +217,7 @@ RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we have a frame */
|
/* Check if we have a frame */
|
||||||
if (RegistrationFrame)
|
if (TargetFrame)
|
||||||
{
|
{
|
||||||
/* Set it as unwinding */
|
/* Set it as unwinding */
|
||||||
ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
|
ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
|
||||||
|
@ -222,30 +237,26 @@ RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
||||||
RtlpCaptureContext(Context);
|
RtlpCaptureContext(Context);
|
||||||
|
|
||||||
/* Pop the current arguments off */
|
/* Pop the current arguments off */
|
||||||
Context->Esp += sizeof(RegistrationFrame) +
|
Context->Esp += sizeof(TargetFrame) +
|
||||||
sizeof(ReturnAddress) +
|
sizeof(TargetIp) +
|
||||||
sizeof(ExceptionRecord) +
|
sizeof(ExceptionRecord) +
|
||||||
sizeof(ReturnValue);
|
sizeof(ReturnValue);
|
||||||
|
|
||||||
/* Set the new value for EAX */
|
/* Set the new value for EAX */
|
||||||
Context->Eax = (ULONG)EaxValue;
|
Context->Eax = (ULONG)ReturnValue;
|
||||||
|
|
||||||
/* Get the current frame */
|
/* Get the current frame */
|
||||||
RegistrationFrame2 = RtlpGetExceptionList();
|
RegistrationFrame = RtlpGetExceptionList();
|
||||||
|
|
||||||
/* Now loop every frame */
|
/* Now loop every frame */
|
||||||
while (RegistrationFrame2 != EXCEPTION_CHAIN_END)
|
while (RegistrationFrame != EXCEPTION_CHAIN_END)
|
||||||
{
|
{
|
||||||
/* If this is the target */
|
/* If this is the target */
|
||||||
if (RegistrationFrame2 == RegistrationFrame)
|
if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE);
|
||||||
{
|
|
||||||
/* Continue execution */
|
|
||||||
ZwContinue(Context, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the frame is too low */
|
/* Check if the frame is too low */
|
||||||
if ((RegistrationFrame) && ((ULONG_PTR)RegistrationFrame <
|
if ((TargetFrame) &&
|
||||||
(ULONG_PTR)RegistrationFrame2))
|
((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame))
|
||||||
{
|
{
|
||||||
/* Create an invalid unwind exception */
|
/* Create an invalid unwind exception */
|
||||||
ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
|
ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
|
||||||
|
@ -258,8 +269,8 @@ RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find out where it ends */
|
/* Find out where it ends */
|
||||||
RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame2 +
|
RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
|
||||||
sizeof(*RegistrationFrame2);
|
sizeof(EXCEPTION_REGISTRATION_RECORD);
|
||||||
|
|
||||||
/* Make sure the registration frame is located within the stack */
|
/* Make sure the registration frame is located within the stack */
|
||||||
if ((RegistrationFrameEnd > StackHigh) ||
|
if ((RegistrationFrameEnd > StackHigh) ||
|
||||||
|
@ -283,30 +294,33 @@ RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
||||||
ExceptionRecord2.NumberParameters = 0;
|
ExceptionRecord2.NumberParameters = 0;
|
||||||
|
|
||||||
/* Raise the exception */
|
/* Raise the exception */
|
||||||
DPRINT1("Frame has bad stack\n");
|
|
||||||
RtlRaiseException(&ExceptionRecord2);
|
RtlRaiseException(&ExceptionRecord2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Call the handler */
|
/* Call the handler */
|
||||||
ReturnValue = RtlpExecuteHandlerForUnwind(ExceptionRecord,
|
Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
|
||||||
RegistrationFrame2,
|
RegistrationFrame,
|
||||||
Context,
|
Context,
|
||||||
&DispatcherContext,
|
&DispatcherContext,
|
||||||
RegistrationFrame2->Handler);
|
RegistrationFrame->
|
||||||
|
Handler);
|
||||||
|
switch (Disposition)
|
||||||
|
{
|
||||||
|
/* Continue searching */
|
||||||
|
case ExceptionContinueSearch:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Collission */
|
||||||
|
case ExceptionCollidedUnwind :
|
||||||
|
|
||||||
|
/* Get the original frame */
|
||||||
|
RegistrationFrame = DispatcherContext.RegistrationPointer;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Anything else */
|
||||||
|
default:
|
||||||
|
|
||||||
/* Handle the dispositions */
|
|
||||||
if (ReturnValue == ExceptionContinueSearch)
|
|
||||||
{
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
else if (ReturnValue == ExceptionCollidedUnwind)
|
|
||||||
{
|
|
||||||
/* Get the previous frame */
|
|
||||||
RegistrationFrame2 = DispatcherContext;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Set up the exception record */
|
/* Set up the exception record */
|
||||||
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
ExceptionRecord2.ExceptionRecord = ExceptionRecord;
|
||||||
ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
|
ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
|
||||||
|
@ -315,22 +329,20 @@ RtlUnwind(PVOID RegistrationFrame OPTIONAL,
|
||||||
|
|
||||||
/* Raise the exception */
|
/* Raise the exception */
|
||||||
RtlRaiseException(&ExceptionRecord2);
|
RtlRaiseException(&ExceptionRecord2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to the next frame */
|
/* Go to the next frame */
|
||||||
OldFrame = RegistrationFrame2;
|
OldFrame = RegistrationFrame;
|
||||||
RegistrationFrame2 = RegistrationFrame2->Next;
|
RegistrationFrame = RegistrationFrame->Next;
|
||||||
|
|
||||||
/* Remove this handler */
|
/* Remove this handler */
|
||||||
if (RegistrationFrame2 != RegistrationFrame)
|
|
||||||
{
|
|
||||||
RtlpSetExceptionList(OldFrame);
|
RtlpSetExceptionList(OldFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we reached the end */
|
/* Check if we reached the end */
|
||||||
if (RegistrationFrame == EXCEPTION_CHAIN_END)
|
if (TargetFrame == EXCEPTION_CHAIN_END)
|
||||||
{
|
{
|
||||||
/* Unwind completed, so we don't exit */
|
/* Unwind completed, so we don't exit */
|
||||||
ZwContinue(Context, FALSE);
|
ZwContinue(Context, FALSE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue