Fixes a bug that occurs when:
- `CoInitializeEx(NULL, COINIT_MULTITHREADED);` is called on thread 1 - `CoInitializeEx(NULL, COINIT_MULTITHREADED);` is called on thread 2 - `CoUninitialize()` is called on thread 1. - `CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);` is called on thread 1.
After this, when attempting to marshal an interface on thread 2, when `ipid_to_ifstub` is called, `apartment_findfromtid()` will find thread 1's STA and not the MTA.
From: Connor McAdams cmcadams@codeweavers.com
It is possible for a thread that creates an MTA to call CoUninitialize() and not destroy the MTA if another thread has entered the MTA in the meantime. If the original thread then creates an STA, subsequent attempts to find the MTA with 'apartment_findfromtid' will get the original thread's STA. To avoid this, don't set a TID value in the stub manager IPID value to indicate that the stub resides in the MTA.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/combase/stubmanager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/combase/stubmanager.c b/dlls/combase/stubmanager.c index 59782b8c623..5bb87c60c1d 100644 --- a/dlls/combase/stubmanager.c +++ b/dlls/combase/stubmanager.c @@ -46,7 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
/* generates an ipid in the following format (similar to native version): * Data1 = apartment-local ipid counter - * Data2 = apartment creator thread ID + * Data2 = apartment creator thread ID, or 0 for an MTA. * Data3 = process ID * Data4 = random value */ @@ -62,7 +62,7 @@ static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) }
ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); - ipid->Data2 = (USHORT)m->apt->tid; + ipid->Data2 = !m->apt->multi_threaded ? (USHORT)m->apt->tid : 0; ipid->Data3 = (USHORT)GetCurrentProcessId(); return S_OK; } @@ -499,6 +499,8 @@ static HRESULT ipid_to_ifstub(const IPID *ipid, struct apartment **stub_apt, /* FIXME: hack for IRemUnknown */ if (ipid->Data2 == 0xffff) *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4); + else if (!ipid->Data2) + *stub_apt = apartment_get_mta(); else *stub_apt = apartment_findfromtid(ipid->Data2); if (!*stub_apt)
On 8/24/22 13:42, Connor McAdams wrote:
From: Connor McAdams cmcadams@codeweavers.com
It is possible for a thread that creates an MTA to call CoUninitialize() and not destroy the MTA if another thread has entered the MTA in the meantime. If the original thread then creates an STA, subsequent attempts to find the MTA with 'apartment_findfromtid' will get the original thread's STA. To avoid this, don't set a TID value in the stub manager IPID value to indicate that the stub resides in the MTA.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/combase/stubmanager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Is it possible to add a test for this?
On Wed Aug 24 20:19:17 2022 +0000, **** wrote:
Zebediah Figura (she/her) replied on the mailing list:
On 8/24/22 13:42, Connor McAdams wrote: > From: Connor McAdams <cmcadams@codeweavers.com> > > It is possible for a thread that creates an MTA to call > CoUninitialize() and not destroy the MTA if another thread has > entered the MTA in the meantime. If the original thread then creates > an STA, subsequent attempts to find the MTA with 'apartment_findfromtid' > will get the original thread's STA. To avoid this, don't set a TID value > in the stub manager IPID value to indicate that the stub resides in the > MTA. > > Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> > --- > dlls/combase/stubmanager.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > Is it possible to add a test for this?
Sure! For some reason I had only looked at `dlls/combase/tests/` and thought all the tests went there, but looks like I could add one to `dlls/ole32/tests/`. I'll do that tomorrow and send a v2.