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];
|
ULONG index = mapping[i];
|
||||||
HRESULT hrobj = qiresults[i].hResult;
|
HRESULT hrobj = qiresults[i].hResult;
|
||||||
if (hrobj == S_OK)
|
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,
|
||||||
This->dest_context_data,
|
This->dest_context_data,
|
||||||
pMQIs[index].pIID, &This->oxid_info,
|
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)
|
static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
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
|
/* we don't want to try and unmarshal or use IRemUnknown if we don't want
|
||||||
* lifetime management */
|
* lifetime management */
|
||||||
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
|
if (This->sorflags & SORFP_NOLIFETIMEMGMT)
|
||||||
return S_FALSE;
|
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);
|
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 */
|
/* already created - return existing object */
|
||||||
*remunk = This->remunk;
|
*remunk = This->remunk;
|
||||||
|
@ -994,10 +1005,10 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk
|
||||||
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
|
stdobjref.ipid = This->oxid_info.ipidRemUnknown;
|
||||||
|
|
||||||
/* do the unmarshal */
|
/* 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->dest_context_data, &IID_IRemUnknown,
|
||||||
&This->oxid_info, (void**)remunk);
|
&This->oxid_info, (void**)remunk);
|
||||||
if (hr == S_OK)
|
if (hr == S_OK && called_in_original_apt)
|
||||||
{
|
{
|
||||||
This->remunk = *remunk;
|
This->remunk = *remunk;
|
||||||
IRemUnknown_AddRef(This->remunk);
|
IRemUnknown_AddRef(This->remunk);
|
||||||
|
|
|
@ -1283,6 +1283,24 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p)
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
IUnknown * proxy = NULL;
|
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);
|
pCoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||||
|
|
||||||
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
|
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",
|
"COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
|
||||||
hr);
|
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();
|
CoUninitialize();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1321,13 +1352,18 @@ static void test_proxy_used_in_wrong_thread(void)
|
||||||
|
|
||||||
ok_more_than_one_lock();
|
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 */
|
/* create a thread that we can misbehave in */
|
||||||
thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
|
thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
|
||||||
|
|
||||||
WaitForSingleObject(thread, INFINITE);
|
WaitForSingleObject(thread, INFINITE);
|
||||||
CloseHandle(thread);
|
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();
|
ok_no_locks();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue