ole32: The identity functions can be used from apartments other than the one the proxy was unmarshaled into.
In this case, don't use the cached This->remunk and don't cache the unmarshaled object in This->remunk.
This commit is contained in:
parent
bf2b49b4e0
commit
dd8a736c3f
|
@ -298,7 +298,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL
|
|||
ULONG index = mapping[i];
|
||||
HRESULT hrobj = qiresults[i].hResult;
|
||||
if (hrobj == S_OK)
|
||||
hrobj = unmarshal_object(&qiresults[i].std, This->parent,
|
||||
hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(),
|
||||
This->dest_context,
|
||||
This->dest_context_data,
|
||||
pMQIs[index].pIID, &This->oxid_info,
|
||||
|
@ -964,14 +964,25 @@ static void proxy_manager_disconnect(struct proxy_manager * This)
|
|||
static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
struct apartment *apt;
|
||||
BOOL called_in_original_apt;
|
||||
|
||||
/* we don't want to try and unmarshal or use IRemUnknown if we don't want
|
||||
* lifetime management */
|
||||
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
|
||||
return S_FALSE;
|
||||
|
||||
apt = COM_CurrentApt();
|
||||
if (!apt)
|
||||
return CO_E_NOTINITIALIZED;
|
||||
|
||||
called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid);
|
||||
|
||||
EnterCriticalSection(&This->cs);
|
||||
if (This->remunk)
|
||||
/* only return the cached object if called from the original apartment.
|
||||
* in future, we might want to make the IRemUnknown proxy callable from any
|
||||
* apartment to avoid these checks */
|
||||
if (This->remunk && called_in_original_apt)
|
||||
{
|
||||
/* already created - return existing object */
|
||||
*remunk = This->remunk;
|
||||
|
@ -994,10 +1005,10 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
|
|||
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
|
||||
|
||||
/* do the unmarshal */
|
||||
hr = unmarshal_object(&stdobjref, This->parent, This->dest_context,
|
||||
hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context,
|
||||
This->dest_context_data, &IID_IRemUnknown,
|
||||
&This->oxid_info, (void**)remunk);
|
||||
if (hr == S_OK)
|
||||
if (hr == S_OK && called_in_original_apt)
|
||||
{
|
||||
This->remunk = *remunk;
|
||||
IRemUnknown_AddRef(This->remunk);
|
||||
|
|
|
@ -1283,6 +1283,24 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p)
|
|||
HRESULT hr;
|
||||
IUnknown * proxy = NULL;
|
||||
|
||||
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
|
||||
todo_wine
|
||||
ok(hr == CO_E_NOTINITIALIZED,
|
||||
"COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n",
|
||||
hr);
|
||||
|
||||
hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy);
|
||||
/* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */
|
||||
trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr);
|
||||
if (SUCCEEDED(hr))
|
||||
IUnknown_Release(proxy);
|
||||
|
||||
hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
|
||||
/* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
|
||||
trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr);
|
||||
if (SUCCEEDED(hr))
|
||||
IUnknown_Release(proxy);
|
||||
|
||||
pCoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
|
||||
|
@ -1291,6 +1309,19 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p)
|
|||
"COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
|
||||
hr);
|
||||
|
||||
hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
|
||||
/* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
|
||||
trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr);
|
||||
|
||||
/* this statement causes Win9x DCOM to crash during CoUninitialize of
|
||||
* other apartment, so don't test this on Win9x (signified by NT-only
|
||||
* export of CoRegisterSurrogateEx) */
|
||||
if (GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx"))
|
||||
/* now be really bad and release the proxy from the wrong apartment */
|
||||
IUnknown_Release(cf);
|
||||
else
|
||||
skip("skipping test for releasing proxy from wrong apartment that will succeed, but cause a crash during CoUninitialize\n");
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
|
@ -1321,13 +1352,18 @@ static void test_proxy_used_in_wrong_thread(void)
|
|||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
/* do a call that will fail, but result in IRemUnknown being used by the proxy */
|
||||
IClassFactory_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
|
||||
|
||||
/* create a thread that we can misbehave in */
|
||||
thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
|
||||
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
CloseHandle(thread);
|
||||
|
||||
IUnknown_Release(pProxy);
|
||||
/* do release statement on Win9x that we should have done above */
|
||||
if (!GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx"))
|
||||
IUnknown_Release(pProxy);
|
||||
|
||||
ok_no_locks();
|
||||
|
||||
|
|
Loading…
Reference in New Issue