- 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:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565592(v=vs.85).aspx
"Yes, for thread termination. No, for user APCs."

svn path=/trunk/; revision=65744
This commit is contained in:
James Tabor 2014-12-18 23:45:11 +00:00
parent 9bc240e832
commit b037edeae8
5 changed files with 87 additions and 11 deletions

View file

@ -13,7 +13,8 @@
#define USER32_CALLBACK_GETCHARSETINFO (9)
#define USER32_CALLBACK_COPYIMAGE (10)
#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
{
@ -138,4 +139,6 @@ NTSTATUS WINAPI
User32CallClientLoadLibraryFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength);
#endif /* __INCLUDE_USER32_CALLBACK_H */

View file

@ -1100,4 +1100,24 @@ co_IntSetWndIcons(VOID)
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 */

View file

@ -71,3 +71,4 @@ co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs);
HANDLE FASTCALL co_IntCopyImage(HANDLE,UINT,INT,INT,UINT);
BOOL FASTCALL co_IntSetWndIcons(VOID);
VOID FASTCALL co_IntDeliverUserAPC(VOID);

View file

@ -1132,17 +1132,22 @@ co_MsqSendMessage(PTHREADINFO ptirec,
/* 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();
/* Don't process messages sent to the thread */
WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
FALSE, (uTimeout ? &Timeout : NULL));
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
UserEnterCo();
if(WaitStatus == STATUS_TIMEOUT)
if (WaitStatus == STATUS_TIMEOUT || WaitStatus == STATUS_USER_APC)
{
/* 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 */
@ -1182,7 +1187,27 @@ co_MsqSendMessage(PTHREADINFO ptirec,
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))
;
@ -1204,7 +1229,7 @@ co_MsqSendMessage(PTHREADINFO ptirec,
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
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;
}
TRACE("MsqSendMessage timed out 2\n");
TRACE("MsqSendMessage timed out 2 Status %p\n",WaitStatus);
break;
}
// Receiving thread passed on and left us hanging with issues still pending.
if ( WaitStatus == STATUS_WAIT_2 )
{
ERR("Receiving Thread woken up dead!\n");
ERR("NB Receiving Thread woken up dead!\n");
Entry = pti->DispatchingMessagesHead.Flink;
while (Entry != &pti->DispatchingMessagesHead)
{
@ -1272,8 +1298,21 @@ co_MsqSendMessage(PTHREADINFO ptirec,
while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1);
}
if(WaitStatus != STATUS_TIMEOUT)
if (uResult) *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
if ( WaitStatus == STATUS_USER_APC )
{
// 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;
}
@ -1972,6 +2011,11 @@ co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
FALSE,
NULL );
UserEnterCo();
if ( ret == STATUS_USER_APC )
{
TRACE("MWFNW User APC\n");
co_IntDeliverUserAPC();
}
return ret;
}

View file

@ -200,6 +200,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
User32CallGetCharsetInfo,
User32CallCopyImageFromKernel,
User32CallSetWndIconsFromKernel,
User32DeliverUserAPC,
};
/*
@ -468,3 +469,10 @@ User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength)
ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
}
NTSTATUS
WINAPI
User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength)
{
return ZwCallbackReturn(0, 0, STATUS_SUCCESS);
}