Added patch to limit cross thread access to ImmSet* functions.

This commit is contained in:
Sebastian Lackner 2014-09-29 02:52:26 +02:00
parent ed22aea5bd
commit acacbd588d
9 changed files with 1039 additions and 1 deletions

View File

@ -35,12 +35,13 @@ Wine. All those differences are also documented on the
Included bugfixes and improvements
==================================
**Bugfixes and features included in the next upcoming release [8]:**
**Bugfixes and features included in the next upcoming release [9]:**
* Correctly treat '.' when checking for empty directories ([Wine Bug #26272](http://bugs.winehq.org/show_bug.cgi?id=26272))
* Do not fail when a used context is passed to wglShareLists ([Wine Bug #11436](http://bugs.winehq.org/show_bug.cgi?id=11436))
* Export ?_BADOFF@std@@3_JB on both i386 and win64 ([Wine Bug #37198](http://bugs.winehq.org/show_bug.cgi?id=37198))
* Fix issues when driver dispatch routine returns different status codes ([Wine Bug #30155](http://bugs.winehq.org/show_bug.cgi?id=30155))
* Limit cross thread access to ImmSet* functions ([Wine Bug #35361](http://bugs.winehq.org/show_bug.cgi?id=35361))
* Send WM_PAINT event during dialog creation ([Wine Bug #35652](http://bugs.winehq.org/show_bug.cgi?id=35652))
* Support for FIND_FIRST_EX_CASE_SENSITIVE flag in FindFirstFileExW
* Unity3D Editor requires ProductId registry value ([Wine Bug #36964](http://bugs.winehq.org/show_bug.cgi?id=36964))

1
debian/changelog vendored
View File

@ -8,6 +8,7 @@ wine-compholio (1.7.28) UNRELEASED; urgency=low
* Added several patches for Unity3D Editor.
* Added patch to fix differences between exception handling behaviour in Wine and Windows.
* Added patch to export ?_BADOFF@std@@3_JB on both i386 and win64.
* Added patch to limit cross thread access to ImmSet* functions.
-- Sebastian Lackner <sebastian@fds-team.de> Sun, 21 Sep 2014 01:44:14 +0200
wine-compholio (1.7.27) unstable; urgency=low

View File

@ -29,6 +29,7 @@ PATCHLIST := \
dbghelp-KdHelp.ok \
dsound-Fast_Mixer.ok \
fonts-Missing_Fonts.ok \
imm32-Cross_Thread_Access.ok \
iphlpapi-TCP_Table.ok \
kernel32-FindFirstFile.ok \
kernel32-GetFinalPathNameByHandle.ok \
@ -339,6 +340,28 @@ fonts-Missing_Fonts.ok:
echo '+ { "fonts-Missing_Fonts", "Torsten Kurbad / Erich E. Hoover", "Implement missing fonts expected by Silverlight. [rev 2]" },'; \
) > fonts-Missing_Fonts.ok
# Patchset imm32-Cross_Thread_Access
# |
# | Included patches:
# | * Limit cross thread access to ImmSet* functions. [by Aric Stewart]
# |
# | This patchset fixes the following Wine bugs:
# | * [#35361] Limit cross thread access to ImmSet* functions
# |
# | Modified files:
# | * dlls/imm32/imm.c, dlls/imm32/tests/imm32.c
# |
.INTERMEDIATE: imm32-Cross_Thread_Access.ok
imm32-Cross_Thread_Access.ok:
$(call APPLY_FILE,imm32-Cross_Thread_Access/0001-imm32-Move-thread-data-from-TLSEntry-to-an-internal-.patch)
$(call APPLY_FILE,imm32-Cross_Thread_Access/0002-imm32-Do-not-let-ImmDestroyContext-destroy-any-defau.patch)
$(call APPLY_FILE,imm32-Cross_Thread_Access/0003-imm32-Use-thread-data-from-target-HWND.patch)
$(call APPLY_FILE,imm32-Cross_Thread_Access/0004-imm32-Restrict-crossthread-Association-and-destructi.patch)
$(call APPLY_FILE,imm32-Cross_Thread_Access/0005-imm32-Limit-cross-thread-access-to-ImmSet-functions.patch)
@( \
echo '+ { "imm32-Cross_Thread_Access", "Aric Stewart", "Limit cross thread access to ImmSet* functions." },'; \
) > imm32-Cross_Thread_Access.ok
# Patchset iphlpapi-TCP_Table
# |
# | Included patches:

View File

@ -0,0 +1,327 @@
From d6e9673ae62469399560736a43368ce7f4ff5a8e Mon Sep 17 00:00:00 2001
From: Aric Stewart <aric@codeweavers.com>
Date: Mon, 8 Sep 2014 21:05:31 -0500
Subject: imm32: Move thread data from TLSEntry to an internal list.
Changes by Sebastian Lackner <sebastian@fds-team.de>:
* Remove ugly logic in IMM_FreeThreadData (id not used at all, avoid unnecessary variables)
* IMM_GetInitializedThreadData shouldn't hold the CS while destroying the context in case of a race-condition
* ImmGetDefaultIMEWnd shouldn't hold the CS while creating a window
---
dlls/imm32/imm.c | 160 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 124 insertions(+), 36 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index 2fa31ac..b617f5a 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -86,12 +86,14 @@ typedef struct _tagTRANSMSG {
} TRANSMSG, *LPTRANSMSG;
typedef struct _tagIMMThreadData {
+ struct list entry;
+ DWORD threadID;
HIMC defaultContext;
HWND hwndDefault;
} IMMThreadData;
-static DWORD tlsIndex = 0;
static struct list ImmHklList = LIST_INIT(ImmHklList);
+static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
/* MSIME messages */
static UINT WM_MSIME_SERVICE;
@@ -110,6 +112,15 @@ static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r'
static const WCHAR szwIME[] = {'I','M','E',0};
+static CRITICAL_SECTION threaddata_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+ 0, 0, &threaddata_cs,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
+};
+static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+
static LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
@@ -220,29 +231,50 @@ static DWORD convert_candidatelist_AtoW(
return ret;
}
-static IMMThreadData* IMM_GetThreadData(void)
+static IMMThreadData* IMM_GetThreadData(DWORD tid)
{
- IMMThreadData* data = TlsGetValue(tlsIndex);
- if (!data)
+ IMMThreadData *data;
+
+ if (!tid) tid = GetCurrentThreadId();
+
+ EnterCriticalSection(&threaddata_cs);
+ LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
{
- data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- sizeof(IMMThreadData));
- TlsSetValue(tlsIndex,data);
- TRACE("Thread Data Created\n");
+ if (data->threadID == tid)
+ return data;
}
+
+ data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IMMThreadData));
+ data->threadID = tid;
+ list_add_head(&ImmThreadDataList, &data->entry);
+ TRACE("Thread Data Created (%x)\n", tid);
+
return data;
}
static void IMM_FreeThreadData(void)
{
- IMMThreadData* data = TlsGetValue(tlsIndex);
- if (data)
+ IMMThreadData *data;
+ DWORD tid = GetCurrentThreadId();
+
+ EnterCriticalSection(&threaddata_cs);
+ LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
{
- IMM_DestroyContext(data->defaultContext);
- DestroyWindow(data->hwndDefault);
- HeapFree(GetProcessHeap(),0,data);
- TRACE("Thread Data Destroyed\n");
+ if (data->threadID == tid)
+ {
+ list_remove(&data->entry);
+ LeaveCriticalSection(&threaddata_cs);
+
+ IMM_DestroyContext(data->defaultContext);
+ DestroyWindow(data->hwndDefault);
+ HeapFree(GetProcessHeap(),0,data);
+ TRACE("Thread Data Destroyed\n");
+
+ return;
+ }
}
+ LeaveCriticalSection(&threaddata_cs);
}
static HMODULE load_graphics_driver(void)
@@ -398,9 +430,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
{
case DLL_PROCESS_ATTACH:
IMM_RegisterMessages();
- tlsIndex = TlsAlloc();
- if (tlsIndex == TLS_OUT_OF_INDEXES)
- return FALSE;
IMM_RegisterIMEClass();
break;
case DLL_THREAD_ATTACH:
@@ -412,7 +441,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
if (lpReserved) break;
IMM_FreeThreadData();
IMM_FreeAllImmHkl();
- TlsFree(tlsIndex);
UnregisterClassW(szwIME, NULL);
break;
}
@@ -469,6 +497,34 @@ static InputContextData* get_imc_data(HIMC hIMC)
return data;
}
+static IMMThreadData* IMM_GetInitializedThreadData(void)
+{
+ IMMThreadData* thread_data;
+ HIMC defaultContext;
+
+ for (;;)
+ {
+ thread_data = IMM_GetThreadData(0);
+ if (thread_data->defaultContext)
+ return thread_data;
+ LeaveCriticalSection(&threaddata_cs);
+
+ /* don't hold the CS while creating the context */
+ defaultContext = ImmCreateContext();
+
+ thread_data = IMM_GetThreadData(0);
+ if (!thread_data->defaultContext)
+ {
+ thread_data->defaultContext = defaultContext;
+ return thread_data;
+ }
+
+ /* someone beat us */
+ LeaveCriticalSection(&threaddata_cs);
+ IMM_DestroyContext(defaultContext);
+ }
+}
+
/***********************************************************************
* ImmAssociateContext (IMM32.@)
*/
@@ -476,31 +532,30 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
{
HIMC old = NULL;
InputContextData *data = get_imc_data(hIMC);
+ IMMThreadData* thread_data = NULL;
TRACE("(%p, %p):\n", hWnd, hIMC);
if(hIMC && !data)
return NULL;
- if (!IMM_GetThreadData()->defaultContext)
- IMM_GetThreadData()->defaultContext = ImmCreateContext();
-
/*
* If already associated just return
*/
if (hIMC && data->IMC.hWnd == hWnd)
return hIMC;
+ thread_data = IMM_GetInitializedThreadData();
if (hWnd)
{
old = RemovePropW(hWnd,szwWineIMCProperty);
if (old == NULL)
- old = IMM_GetThreadData()->defaultContext;
+ old = thread_data->defaultContext;
else if (old == (HIMC)-1)
old = NULL;
- if (hIMC != IMM_GetThreadData()->defaultContext)
+ if (hIMC != thread_data->defaultContext)
{
if (hIMC == NULL) /* Meaning disable imm for that window*/
SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
@@ -515,6 +570,7 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
old_data->IMC.hWnd = NULL;
}
}
+ LeaveCriticalSection(&threaddata_cs);
if (!hIMC)
return old;
@@ -556,12 +612,17 @@ static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
*/
BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
{
+ IMMThreadData* thread_data = NULL;
+ HIMC defaultContext = NULL;
+
TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
- if (!IMM_GetThreadData()->defaultContext)
- IMM_GetThreadData()->defaultContext = ImmCreateContext();
+ thread_data = IMM_GetInitializedThreadData();
+ defaultContext = thread_data->defaultContext;
+ LeaveCriticalSection(&threaddata_cs);
- if (!hWnd) return FALSE;
+ if (!hWnd)
+ return FALSE;
switch (dwFlags)
{
@@ -569,7 +630,7 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
ImmAssociateContext(hWnd,hIMC);
return TRUE;
case IACE_DEFAULT:
- ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext);
+ ImmAssociateContext(hWnd,defaultContext);
return TRUE;
case IACE_IGNORENOCONTEXT:
if (GetPropW(hWnd,szwWineIMCProperty))
@@ -744,7 +805,11 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
*/
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{
- if (hIMC != IMM_GetThreadData()->defaultContext)
+ IMMThreadData* thread_data = IMM_GetThreadData(0);
+ HIMC defaultContext = thread_data->defaultContext;
+ LeaveCriticalSection(&threaddata_cs);
+
+ if (hIMC != defaultContext)
return IMM_DestroyContext(hIMC);
else
return FALSE;
@@ -1410,6 +1475,7 @@ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
HIMC WINAPI ImmGetContext(HWND hWnd)
{
HIMC rc;
+ IMMThreadData* thread_data;
TRACE("%p\n", hWnd);
@@ -1418,20 +1484,21 @@ HIMC WINAPI ImmGetContext(HWND hWnd)
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
- if (!IMM_GetThreadData()->defaultContext)
- IMM_GetThreadData()->defaultContext = ImmCreateContext();
+ thread_data = IMM_GetInitializedThreadData();
rc = GetPropW(hWnd,szwWineIMCProperty);
if (rc == (HIMC)-1)
rc = NULL;
else if (rc == NULL)
- rc = IMM_GetThreadData()->defaultContext;
+ rc = thread_data->defaultContext;
if (rc)
{
InputContextData *data = rc;
data->IMC.hWnd = hWnd;
}
+ LeaveCriticalSection(&threaddata_cs);
+
TRACE("returning %p\n", rc);
return rc;
@@ -1539,11 +1606,32 @@ BOOL WINAPI ImmGetConversionStatus(
*/
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{
- if (IMM_GetThreadData()->hwndDefault == NULL)
- IMM_GetThreadData()->hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW,
- szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0);
- TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault);
- return IMM_GetThreadData()->hwndDefault;
+ IMMThreadData* thread_data;
+ HWND ret;
+
+ for (;;)
+ {
+ thread_data = IMM_GetThreadData(0);
+ ret = thread_data->hwndDefault;
+ LeaveCriticalSection(&threaddata_cs);
+ if (ret) return ret;
+
+ /* don't hold the CS while creating the window */
+ ret = CreateWindowExW( WS_EX_TOOLWINDOW,
+ szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0);
+
+ thread_data = IMM_GetThreadData(0);
+ if (!thread_data->hwndDefault)
+ {
+ thread_data->hwndDefault = ret;
+ LeaveCriticalSection(&threaddata_cs);
+ return ret;
+ }
+
+ /* someone beat us */
+ LeaveCriticalSection(&threaddata_cs);
+ DestroyWindow(ret);
+ }
}
/***********************************************************************
--
2.1.1

View File

@ -0,0 +1,72 @@
From bf064c6ac3f0124810e2afadff7b0cdcbf032765 Mon Sep 17 00:00:00 2001
From: Aric Stewart <aric@codeweavers.com>
Date: Mon, 29 Sep 2014 02:28:32 +0200
Subject: imm32: Do not let ImmDestroyContext destroy any default contexts.
optimization suggested by Nikolay Sivov
---
dlls/imm32/imm.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index b617f5a..ec03c62 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -74,6 +74,7 @@ typedef struct tagInputContextData
ImmHkl *immKbd;
UINT lastVK;
+ BOOL threadDefault;
DWORD magic;
} InputContextData;
@@ -128,6 +129,7 @@ static LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
#define is_kbd_ime_unicode(p) (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
static BOOL IMM_DestroyContext(HIMC hIMC);
+static InputContextData* get_imc_data(HIMC hIMC);
static inline WCHAR *strdupAtoW( const char *str )
{
@@ -253,6 +255,16 @@ static IMMThreadData* IMM_GetThreadData(DWORD tid)
return data;
}
+static BOOL IMM_IsDefaultContext(HIMC imc)
+{
+ InputContextData *data = get_imc_data(imc);
+
+ if (!data)
+ return FALSE;
+
+ return data->threadDefault;
+}
+
static void IMM_FreeThreadData(void)
{
IMMThreadData *data;
@@ -511,6 +523,8 @@ static IMMThreadData* IMM_GetInitializedThreadData(void)
/* don't hold the CS while creating the context */
defaultContext = ImmCreateContext();
+ if (defaultContext)
+ ((InputContextData*)defaultContext)->threadDefault = TRUE;
thread_data = IMM_GetThreadData(0);
if (!thread_data->defaultContext)
@@ -805,11 +819,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
*/
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{
- IMMThreadData* thread_data = IMM_GetThreadData(0);
- HIMC defaultContext = thread_data->defaultContext;
- LeaveCriticalSection(&threaddata_cs);
-
- if (hIMC != defaultContext)
+ if (!IMM_IsDefaultContext(hIMC))
return IMM_DestroyContext(hIMC);
else
return FALSE;
--
2.1.1

View File

@ -0,0 +1,210 @@
From e900bc5a15f15278dc22dbc447ab5f7d18e0ce14 Mon Sep 17 00:00:00 2001
From: Aric Stewart <aric@codeweavers.com>
Date: Mon, 29 Sep 2014 02:42:05 +0200
Subject: imm32: Use thread data from target HWND.
---
dlls/imm32/imm.c | 61 +++++++++++++++++++++++++++++++++++++++++-------
dlls/imm32/tests/imm32.c | 21 +++++++++++------
2 files changed, 66 insertions(+), 16 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index ec03c62..f7fca3f 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -255,6 +255,21 @@ static IMMThreadData* IMM_GetThreadData(DWORD tid)
return data;
}
+static IMMThreadData* IMM_GetThreadDataForWindow(HWND hwnd)
+{
+ DWORD process;
+ DWORD thread = 0;
+
+ if (hwnd)
+ {
+ thread = GetWindowThreadProcessId(hwnd, &process);
+ if (process != GetCurrentProcessId())
+ return NULL;
+ }
+
+ return IMM_GetThreadData(thread);
+}
+
static BOOL IMM_IsDefaultContext(HIMC imc)
{
InputContextData *data = get_imc_data(imc);
@@ -509,14 +524,16 @@ static InputContextData* get_imc_data(HIMC hIMC)
return data;
}
-static IMMThreadData* IMM_GetInitializedThreadData(void)
+static IMMThreadData* IMM_GetInitializedThreadData(HWND hWnd)
{
IMMThreadData* thread_data;
HIMC defaultContext;
for (;;)
{
- thread_data = IMM_GetThreadData(0);
+ thread_data = IMM_GetThreadDataForWindow(hWnd);
+ if (!thread_data)
+ return NULL;
if (thread_data->defaultContext)
return thread_data;
LeaveCriticalSection(&threaddata_cs);
@@ -526,7 +543,12 @@ static IMMThreadData* IMM_GetInitializedThreadData(void)
if (defaultContext)
((InputContextData*)defaultContext)->threadDefault = TRUE;
- thread_data = IMM_GetThreadData(0);
+ thread_data = IMM_GetThreadDataForWindow(hWnd);
+ if (!thread_data)
+ {
+ IMM_DestroyContext(defaultContext);
+ return NULL;
+ }
if (!thread_data->defaultContext)
{
thread_data->defaultContext = defaultContext;
@@ -559,7 +581,10 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
if (hIMC && data->IMC.hWnd == hWnd)
return hIMC;
- thread_data = IMM_GetInitializedThreadData();
+ thread_data = IMM_GetInitializedThreadData(hWnd);
+ if (!thread_data)
+ return NULL;
+
if (hWnd)
{
old = RemovePropW(hWnd,szwWineIMCProperty);
@@ -631,7 +656,10 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
- thread_data = IMM_GetInitializedThreadData();
+ thread_data = IMM_GetInitializedThreadData(hWnd);
+ if (!thread_data)
+ return FALSE;
+
defaultContext = thread_data->defaultContext;
LeaveCriticalSection(&threaddata_cs);
@@ -1495,7 +1523,10 @@ HIMC WINAPI ImmGetContext(HWND hWnd)
return NULL;
}
- thread_data = IMM_GetInitializedThreadData();
+ thread_data = IMM_GetInitializedThreadData(hWnd);
+ if (!thread_data)
+ return NULL;
+
rc = GetPropW(hWnd,szwWineIMCProperty);
if (rc == (HIMC)-1)
rc = NULL;
@@ -1618,19 +1649,31 @@ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{
IMMThreadData* thread_data;
HWND ret;
+ DWORD tid;
for (;;)
{
- thread_data = IMM_GetThreadData(0);
+ thread_data = IMM_GetThreadDataForWindow(hWnd);
+ if (!thread_data)
+ return NULL;
ret = thread_data->hwndDefault;
+ tid = thread_data->threadID;
LeaveCriticalSection(&threaddata_cs);
- if (ret) return ret;
+
+ /* don't create windows for other threads */
+ if (ret || tid != GetCurrentThreadId())
+ return ret;
/* don't hold the CS while creating the window */
ret = CreateWindowExW( WS_EX_TOOLWINDOW,
szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0);
- thread_data = IMM_GetThreadData(0);
+ thread_data = IMM_GetThreadDataForWindow(hWnd);
+ if (!thread_data)
+ {
+ DestroyWindow(ret);
+ return NULL;
+ }
if (!thread_data->hwndDefault)
{
thread_data->hwndDefault = ret;
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index 4c0a888..2471634 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -425,15 +425,17 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
HWND hwnd2;
COMPOSITIONFORM cf;
POINT pt;
+ MSG msg;
+
igc_threadinfo *info= (igc_threadinfo*)lpParam;
info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
h1 = ImmGetContext(hwnd);
- todo_wine ok(info->himc == h1, "hwnd context changed in new thread\n");
+ ok(info->himc == h1, "hwnd context changed in new thread\n");
h2 = ImmGetContext(info->hwnd);
- todo_wine ok(h2 != h1, "new hwnd in new thread should have different context\n");
+ ok(h2 != h1, "new hwnd in new thread should have different context\n");
info->himc = h2;
ImmReleaseContext(hwnd,h1);
@@ -452,7 +454,12 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
ImmSetStatusWindowPos(h1, &pt);
SetEvent(info->event);
- Sleep(INFINITE);
+
+ while(GetMessageW(&msg, 0, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
return 1;
}
@@ -477,8 +484,8 @@ static void test_ImmThreads(void)
otherHimc = ImmGetContext(threadinfo.hwnd);
- todo_wine ok(himc != otherHimc, "Windows from other threads should have different himc\n");
- todo_wine ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
+ ok(himc != otherHimc, "Windows from other threads should have different himc\n");
+ ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
if (0) /* FIXME: Causes wine to hang */
{
@@ -566,7 +573,7 @@ static void test_ImmThreads(void)
ok (rc == 1, "ImmGetCandidateWindow should succeed\n");
rc = ImmGetCandidateWindow(otherHimc, 0, &cdf);
- todo_wine ok (rc == 0, "ImmGetCandidateWindow should fail\n");
+ ok (rc == 0, "ImmGetCandidateWindow should fail\n");
rc = ImmSetCandidateWindow(otherHimc, &cdf);
todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
@@ -577,7 +584,7 @@ static void test_ImmThreads(void)
TerminateThread(hThread, 1);
himc = ImmGetContext(GetDesktopWindow());
- todo_wine ok(himc == NULL, "Should not be able to get himc from other process window\n");
+ ok(himc == NULL, "Should not be able to get himc from other process window\n");
}
static void test_ImmIsUIMessage(void)
--
2.1.1

View File

@ -0,0 +1,227 @@
From f5b7d0ea864e0ab6fb28f8ff492730a4d748b356 Mon Sep 17 00:00:00 2001
From: Aric Stewart <aric@codeweavers.com>
Date: Mon, 29 Sep 2014 02:48:08 +0200
Subject: imm32: Restrict crossthread Association and destruction.
---
dlls/imm32/imm.c | 26 ++++++++++++++++++++-
dlls/imm32/tests/imm32.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index f7fca3f..efbd623 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -71,6 +71,7 @@ typedef struct tagInputContextData
{
DWORD dwLock;
INPUTCONTEXT IMC;
+ DWORD threadID;
ImmHkl *immKbd;
UINT lastVK;
@@ -561,6 +562,25 @@ static IMMThreadData* IMM_GetInitializedThreadData(HWND hWnd)
}
}
+static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
+{
+ DWORD tid = GetCurrentThreadId();
+ InputContextData *data;
+
+ if (hWnd)
+ {
+ DWORD process;
+ DWORD thread;
+
+ thread = GetWindowThreadProcessId(hWnd, &process);
+ if (thread != tid || process != GetCurrentProcessId())
+ return TRUE;
+ }
+
+ data = get_imc_data(hIMC);
+ return (data && data->threadID != tid);
+}
+
/***********************************************************************
* ImmAssociateContext (IMM32.@)
*/
@@ -581,6 +601,9 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
if (hIMC && data->IMC.hWnd == hWnd)
return hIMC;
+ if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
+ return NULL;
+
thread_data = IMM_GetInitializedThreadData(hWnd);
if (!thread_data)
return NULL;
@@ -808,6 +831,7 @@ HIMC WINAPI ImmCreateContext(void)
IMM_DestroyContext(new_context);
return 0;
}
+ new_context->threadID = GetCurrentThreadId();
SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
new_context->immKbd->uSelected++;
@@ -847,7 +871,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
*/
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{
- if (!IMM_IsDefaultContext(hIMC))
+ if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
return IMM_DestroyContext(hIMC);
else
return FALSE;
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index 2471634..a64f9da 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -416,6 +416,7 @@ typedef struct _igc_threadinfo {
HWND hwnd;
HANDLE event;
HIMC himc;
+ HIMC u_himc;
} igc_threadinfo;
@@ -424,6 +425,7 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
HIMC h1,h2;
HWND hwnd2;
COMPOSITIONFORM cf;
+ CANDIDATEFORM cdf;
POINT pt;
MSG msg;
@@ -452,6 +454,13 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
/* priming for later tests */
ImmSetCompositionWindow(h1, &cf);
ImmSetStatusWindowPos(h1, &pt);
+ info->u_himc = ImmCreateContext();
+ ImmSetOpenStatus(info->u_himc, TRUE);
+ cdf.dwIndex = 0;
+ cdf.dwStyle = CFS_CANDIDATEPOS;
+ cdf.ptCurrentPos.x = 0;
+ cdf.ptCurrentPos.y = 0;
+ ImmSetCandidateWindow(info->u_himc, &cdf);
SetEvent(info->event);
@@ -487,15 +496,23 @@ static void test_ImmThreads(void)
ok(himc != otherHimc, "Windows from other threads should have different himc\n");
ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
- if (0) /* FIXME: Causes wine to hang */
- {
h1 = ImmAssociateContext(hwnd,otherHimc);
ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
h1 = ImmGetContext(hwnd);
ok(h1 == himc, "Context for window should remain unchanged\n");
ImmReleaseContext(hwnd,h1);
- }
+ h1 = ImmAssociateContext(hwnd, threadinfo.u_himc);
+ ok (h1 == NULL, "Should fail to associate a context from a different thread\n");
+ h1 = ImmGetContext(hwnd);
+ ok(h1 == himc, "Context for window should remain unchanged\n");
+ ImmReleaseContext(hwnd,h1);
+
+ h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc);
+ ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n");
+ h1 = ImmGetContext(threadinfo.hwnd);
+ ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n");
+ ImmReleaseContext(threadinfo.hwnd,h1);
/* OpenStatus */
rc = ImmSetOpenStatus(himc, TRUE);
@@ -509,8 +526,12 @@ static void test_ImmThreads(void)
rc = ImmSetOpenStatus(otherHimc, TRUE);
todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
+ rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE);
+ todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
rc = ImmGetOpenStatus(otherHimc);
todo_wine ok(rc == 0, "ImmGetOpenStatus failed\n");
+ rc = ImmGetOpenStatus(threadinfo.u_himc);
+ ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n");
rc = ImmSetOpenStatus(otherHimc, FALSE);
todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
rc = ImmGetOpenStatus(otherHimc);
@@ -524,8 +545,12 @@ static void test_ImmThreads(void)
rc = ImmGetCompositionFontA(otherHimc, &lf);
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n");
+ rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf);
+ ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n");
rc = ImmSetCompositionFontA(otherHimc, &lf);
todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
+ rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf);
+ todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
/* CompositionWindow */
rc = ImmSetCompositionWindow(himc, &cf);
@@ -535,8 +560,12 @@ static void test_ImmThreads(void)
rc = ImmSetCompositionWindow(otherHimc, &cf);
todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
+ rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf);
+ todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
rc = ImmGetCompositionWindow(otherHimc, &cf);
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
+ rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf);
+ ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
/* ConversionStatus */
rc = ImmGetConversionStatus(himc, &status, &sentence);
@@ -546,8 +575,12 @@ static void test_ImmThreads(void)
rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
+ rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence);
+ ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
rc = ImmSetConversionStatus(otherHimc, status, sentence);
todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
+ rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence);
+ todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
/* StatusWindowPos */
rc = ImmSetStatusWindowPos(himc, &pt);
@@ -557,8 +590,24 @@ static void test_ImmThreads(void)
rc = ImmSetStatusWindowPos(otherHimc, &pt);
todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
+ rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt);
+ todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
rc = ImmGetStatusWindowPos(otherHimc, &pt);
ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
+ rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt);
+ ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
+
+ h1 = ImmAssociateContext(threadinfo.hwnd, NULL);
+ ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n");
+ h1 = ImmGetContext(threadinfo.hwnd);
+ ok (h1 == NULL, "CrossThread window context should be NULL\n");
+ h1 = ImmAssociateContext(threadinfo.hwnd, h1);
+ ok (h1 == NULL, "Resetting cross thread context should fail\n");
+ h1 = ImmGetContext(threadinfo.hwnd);
+ ok (h1 == NULL, "CrossThread window context should still be NULL\n");
+
+ rc = ImmDestroyContext(threadinfo.u_himc);
+ ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n");
/* Candidate Window */
rc = ImmGetCandidateWindow(himc, 0, &cdf);
@@ -576,6 +625,10 @@ static void test_ImmThreads(void)
ok (rc == 0, "ImmGetCandidateWindow should fail\n");
rc = ImmSetCandidateWindow(otherHimc, &cdf);
todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
+ rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf);
+ ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n");
+ rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf);
+ todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
ImmReleaseContext(threadinfo.hwnd,otherHimc);
ImmReleaseContext(hwnd,himc);
--
2.1.1

View File

@ -0,0 +1,173 @@
From e76b9bfb0d47f7df14256e62a57585660adcf8c0 Mon Sep 17 00:00:00 2001
From: Aric Stewart <aric@codeweavers.com>
Date: Mon, 8 Sep 2014 21:06:13 -0500
Subject: imm32: Limit cross thread access to ImmSet* functions.
---
dlls/imm32/imm.c | 21 +++++++++++++++++++++
dlls/imm32/tests/imm32.c | 28 ++++++++++++++--------------
2 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index efbd623..222c86e 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -2311,6 +2311,9 @@ BOOL WINAPI ImmSetCandidateWindow(
if (!data || !lpCandidate)
return FALSE;
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
TRACE("\t%x, %x, (%i,%i), (%i,%i - %i,%i)\n",
lpCandidate->dwIndex, lpCandidate->dwStyle,
lpCandidate->ptCurrentPos.x, lpCandidate->ptCurrentPos.y,
@@ -2341,6 +2344,9 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
LF_FACESIZE);
@@ -2364,6 +2370,9 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
data->IMC.lfFont.W = *lplf;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
@@ -2505,6 +2514,9 @@ BOOL WINAPI ImmSetCompositionWindow(
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
data->IMC.cfCompForm = *lpCompForm;
if (IsWindowVisible(data->immKbd->UIWnd))
@@ -2539,6 +2551,9 @@ BOOL WINAPI ImmSetConversionStatus(
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
if ( fdwConversion != data->IMC.fdwConversion )
{
oldConversion = data->IMC.fdwConversion;
@@ -2572,6 +2587,9 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
if (data->immKbd->UIWnd == NULL)
{
/* create the ime window */
@@ -2608,6 +2626,9 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
return FALSE;
}
+ if (IMM_IsCrossThreadAccess(NULL, hIMC))
+ return FALSE;
+
TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y);
data->IMC.ptStatusWndPos = *lpptPos;
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index a64f9da..d7eec44 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -525,15 +525,15 @@ static void test_ImmThreads(void)
ok(rc == 0, "ImmGetOpenStatus failed\n");
rc = ImmSetOpenStatus(otherHimc, TRUE);
- todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
+ ok(rc == 0, "ImmSetOpenStatus should fail\n");
rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE);
- todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
+ ok(rc == 0, "ImmSetOpenStatus should fail\n");
rc = ImmGetOpenStatus(otherHimc);
- todo_wine ok(rc == 0, "ImmGetOpenStatus failed\n");
+ ok(rc == 0, "ImmGetOpenStatus failed\n");
rc = ImmGetOpenStatus(threadinfo.u_himc);
ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n");
rc = ImmSetOpenStatus(otherHimc, FALSE);
- todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
+ ok(rc == 0, "ImmSetOpenStatus should fail\n");
rc = ImmGetOpenStatus(otherHimc);
ok(rc == 0, "ImmGetOpenStatus failed\n");
@@ -548,9 +548,9 @@ static void test_ImmThreads(void)
rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf);
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n");
rc = ImmSetCompositionFontA(otherHimc, &lf);
- todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
+ ok(rc == 0, "ImmSetCompositionFont should fail\n");
rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf);
- todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
+ ok(rc == 0, "ImmSetCompositionFont should fail\n");
/* CompositionWindow */
rc = ImmSetCompositionWindow(himc, &cf);
@@ -559,9 +559,9 @@ static void test_ImmThreads(void)
ok(rc != 0, "ImmGetCompositionWindow failed\n");
rc = ImmSetCompositionWindow(otherHimc, &cf);
- todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
+ ok(rc == 0, "ImmSetCompositionWindow should fail\n");
rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf);
- todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
+ ok(rc == 0, "ImmSetCompositionWindow should fail\n");
rc = ImmGetCompositionWindow(otherHimc, &cf);
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf);
@@ -578,9 +578,9 @@ static void test_ImmThreads(void)
rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence);
ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
rc = ImmSetConversionStatus(otherHimc, status, sentence);
- todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
+ ok(rc == 0, "ImmSetConversionStatus should fail\n");
rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence);
- todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
+ ok(rc == 0, "ImmSetConversionStatus should fail\n");
/* StatusWindowPos */
rc = ImmSetStatusWindowPos(himc, &pt);
@@ -589,9 +589,9 @@ static void test_ImmThreads(void)
ok(rc != 0, "ImmGetStatusWindowPos failed\n");
rc = ImmSetStatusWindowPos(otherHimc, &pt);
- todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
+ ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt);
- todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
+ ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
rc = ImmGetStatusWindowPos(otherHimc, &pt);
ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt);
@@ -624,11 +624,11 @@ static void test_ImmThreads(void)
rc = ImmGetCandidateWindow(otherHimc, 0, &cdf);
ok (rc == 0, "ImmGetCandidateWindow should fail\n");
rc = ImmSetCandidateWindow(otherHimc, &cdf);
- todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
+ ok (rc == 0, "ImmSetCandidateWindow should fail\n");
rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf);
ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n");
rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf);
- todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
+ ok (rc == 0, "ImmSetCandidateWindow should fail\n");
ImmReleaseContext(threadinfo.hwnd,otherHimc);
ImmReleaseContext(hwnd,himc);
--
2.1.1

View File

@ -0,0 +1,4 @@
Author: Aric Stewart
Subject: Limit cross thread access to ImmSet* functions.
Revision: 1
Fixes: [35361] Limit cross thread access to ImmSet* functions