mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 06:33:01 +00:00
[Win32k]
- Crash is due to receiving an APC for the current sending thread. Prematurely freeing the data block and while the receiving thread did not have a chance to process it. Interception and calling back to user mode will allow thread to go away. What about the memory block, is it still allocated? A cleaver Hack can fix this, but still the application crashed leaving issues and trash laying about. See CORE-8779.
Reference:
ff565592
(v=vs.85).aspx
"Yes, for thread termination. No, for user APCs."
svn path=/trunk/; revision=65744
This commit is contained in:
parent
9bc240e832
commit
b037edeae8
5 changed files with 87 additions and 11 deletions
|
@ -13,7 +13,8 @@
|
||||||
#define USER32_CALLBACK_GETCHARSETINFO (9)
|
#define USER32_CALLBACK_GETCHARSETINFO (9)
|
||||||
#define USER32_CALLBACK_COPYIMAGE (10)
|
#define USER32_CALLBACK_COPYIMAGE (10)
|
||||||
#define USER32_CALLBACK_SETWNDICONS (11)
|
#define USER32_CALLBACK_SETWNDICONS (11)
|
||||||
#define USER32_CALLBACK_MAXIMUM (11)
|
#define USER32_CALLBACK_DELIVERUSERAPC (12)
|
||||||
|
#define USER32_CALLBACK_MAXIMUM (12)
|
||||||
|
|
||||||
typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS
|
typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS
|
||||||
{
|
{
|
||||||
|
@ -138,4 +139,6 @@ NTSTATUS WINAPI
|
||||||
User32CallClientLoadLibraryFromKernel(PVOID Arguments, ULONG ArgumentLength);
|
User32CallClientLoadLibraryFromKernel(PVOID Arguments, ULONG ArgumentLength);
|
||||||
NTSTATUS WINAPI
|
NTSTATUS WINAPI
|
||||||
User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength);
|
User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength);
|
||||||
|
NTSTATUS WINAPI
|
||||||
|
User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength);
|
||||||
#endif /* __INCLUDE_USER32_CALLBACK_H */
|
#endif /* __INCLUDE_USER32_CALLBACK_H */
|
||||||
|
|
|
@ -1100,4 +1100,24 @@ co_IntSetWndIcons(VOID)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID FASTCALL
|
||||||
|
co_IntDeliverUserAPC(VOID)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
UserLeaveCo();
|
||||||
|
|
||||||
|
Status = KeUserModeCallback(USER32_CALLBACK_DELIVERUSERAPC,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
|
||||||
|
UserEnterCo();
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ERR("Delivering User APC callback failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -71,3 +71,4 @@ co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs);
|
||||||
HANDLE FASTCALL co_IntCopyImage(HANDLE,UINT,INT,INT,UINT);
|
HANDLE FASTCALL co_IntCopyImage(HANDLE,UINT,INT,INT,UINT);
|
||||||
|
|
||||||
BOOL FASTCALL co_IntSetWndIcons(VOID);
|
BOOL FASTCALL co_IntSetWndIcons(VOID);
|
||||||
|
VOID FASTCALL co_IntDeliverUserAPC(VOID);
|
||||||
|
|
|
@ -1132,17 +1132,22 @@ co_MsqSendMessage(PTHREADINFO ptirec,
|
||||||
|
|
||||||
/* We can't access the Message anymore since it could have already been deleted! */
|
/* We can't access the Message anymore since it could have already been deleted! */
|
||||||
|
|
||||||
if(Block)
|
if (Block)
|
||||||
{
|
{
|
||||||
|
PVOID WaitObjects[2];
|
||||||
|
|
||||||
|
WaitObjects[0] = &CompletionEvent; // Wait 0
|
||||||
|
WaitObjects[1] = ptirec->pEThread; // Wait 1
|
||||||
|
|
||||||
UserLeaveCo();
|
UserLeaveCo();
|
||||||
|
|
||||||
/* Don't process messages sent to the thread */
|
/* Don't process messages sent to the thread */
|
||||||
WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
|
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
|
||||||
FALSE, (uTimeout ? &Timeout : NULL));
|
UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
|
||||||
|
|
||||||
UserEnterCo();
|
UserEnterCo();
|
||||||
|
|
||||||
if(WaitStatus == STATUS_TIMEOUT)
|
if (WaitStatus == STATUS_TIMEOUT || WaitStatus == STATUS_USER_APC)
|
||||||
{
|
{
|
||||||
/* Look up if the message has not yet dispatched, if so
|
/* Look up if the message has not yet dispatched, if so
|
||||||
make sure it can't pass a result and it must not set the completion event anymore */
|
make sure it can't pass a result and it must not set the completion event anymore */
|
||||||
|
@ -1182,7 +1187,27 @@ co_MsqSendMessage(PTHREADINFO ptirec,
|
||||||
Entry = Entry->Flink;
|
Entry = Entry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("MsqSendMessage (blocked) timed out 1\n");
|
TRACE("MsqSendMessage (blocked) timed out 1 Status %p\n",WaitStatus);
|
||||||
|
|
||||||
|
}
|
||||||
|
// Receiving thread passed on and left us hanging with issues still pending.
|
||||||
|
if ( WaitStatus == STATUS_WAIT_1 )
|
||||||
|
{
|
||||||
|
ERR("Bk Receiving Thread woken up dead!\n");
|
||||||
|
Entry = pti->DispatchingMessagesHead.Flink;
|
||||||
|
while (Entry != &pti->DispatchingMessagesHead)
|
||||||
|
{
|
||||||
|
if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
|
||||||
|
== Message)
|
||||||
|
{
|
||||||
|
Message->CompletionEvent = NULL;
|
||||||
|
Message->Result = NULL;
|
||||||
|
RemoveEntryList(&Message->DispatchingListEntry);
|
||||||
|
Message->DispatchingListEntry.Flink = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Entry = Entry->Flink;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (co_MsqDispatchOneSentMessage(pti))
|
while (co_MsqDispatchOneSentMessage(pti))
|
||||||
;
|
;
|
||||||
|
@ -1204,7 +1229,7 @@ co_MsqSendMessage(PTHREADINFO ptirec,
|
||||||
|
|
||||||
UserEnterCo();
|
UserEnterCo();
|
||||||
|
|
||||||
if(WaitStatus == STATUS_TIMEOUT)
|
if (WaitStatus == STATUS_TIMEOUT || WaitStatus == STATUS_USER_APC)
|
||||||
{
|
{
|
||||||
/* Look up if the message has not yet been dispatched, if so
|
/* Look up if the message has not yet been dispatched, if so
|
||||||
make sure it can't pass a result and it must not set the completion event anymore */
|
make sure it can't pass a result and it must not set the completion event anymore */
|
||||||
|
@ -1244,13 +1269,14 @@ co_MsqSendMessage(PTHREADINFO ptirec,
|
||||||
Entry = Entry->Flink;
|
Entry = Entry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("MsqSendMessage timed out 2\n");
|
TRACE("MsqSendMessage timed out 2 Status %p\n",WaitStatus);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Receiving thread passed on and left us hanging with issues still pending.
|
// Receiving thread passed on and left us hanging with issues still pending.
|
||||||
if ( WaitStatus == STATUS_WAIT_2 )
|
if ( WaitStatus == STATUS_WAIT_2 )
|
||||||
{
|
{
|
||||||
ERR("Receiving Thread woken up dead!\n");
|
ERR("NB Receiving Thread woken up dead!\n");
|
||||||
Entry = pti->DispatchingMessagesHead.Flink;
|
Entry = pti->DispatchingMessagesHead.Flink;
|
||||||
while (Entry != &pti->DispatchingMessagesHead)
|
while (Entry != &pti->DispatchingMessagesHead)
|
||||||
{
|
{
|
||||||
|
@ -1272,8 +1298,21 @@ co_MsqSendMessage(PTHREADINFO ptirec,
|
||||||
while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1);
|
while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(WaitStatus != STATUS_TIMEOUT)
|
if ( WaitStatus == STATUS_USER_APC )
|
||||||
if (uResult) *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
|
{
|
||||||
|
// The current thread is dying!
|
||||||
|
TRACE("User APC\n");
|
||||||
|
co_IntDeliverUserAPC();
|
||||||
|
ERR("User APC Returned\n"); // Should not see this message.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitStatus != STATUS_TIMEOUT)
|
||||||
|
{
|
||||||
|
if (uResult)
|
||||||
|
{
|
||||||
|
*uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return WaitStatus;
|
return WaitStatus;
|
||||||
}
|
}
|
||||||
|
@ -1972,6 +2011,11 @@ co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
|
||||||
FALSE,
|
FALSE,
|
||||||
NULL );
|
NULL );
|
||||||
UserEnterCo();
|
UserEnterCo();
|
||||||
|
if ( ret == STATUS_USER_APC )
|
||||||
|
{
|
||||||
|
TRACE("MWFNW User APC\n");
|
||||||
|
co_IntDeliverUserAPC();
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
|
||||||
User32CallGetCharsetInfo,
|
User32CallGetCharsetInfo,
|
||||||
User32CallCopyImageFromKernel,
|
User32CallCopyImageFromKernel,
|
||||||
User32CallSetWndIconsFromKernel,
|
User32CallSetWndIconsFromKernel,
|
||||||
|
User32DeliverUserAPC,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -468,3 +469,10 @@ User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength)
|
||||||
ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
|
ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
|
||||||
return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
|
return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
WINAPI
|
||||||
|
User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength)
|
||||||
|
{
|
||||||
|
return ZwCallbackReturn(0, 0, STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue