Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement unwrapping a ComWrappers CCW when dumping a stowed exception. #36360

Merged
merged 3 commits into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/src/debug/daccess/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CLR_DIR}/src/debug/ee)
include_directories(${CLR_DIR}/src/gcdump)
include_directories(${CLR_DIR}/src/interop/inc)

if(CLR_CMAKE_HOST_UNIX)
include_directories(${GENERATED_INCLUDE_DIR})
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/src/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,10 @@ class ClrDataAccess
PTR_IUnknown DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex);
#endif

#ifdef FEATURE_COMWRAPPERS
HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef);
#endif

static LONG s_procInit;

public:
Expand Down
22 changes: 19 additions & 3 deletions src/coreclr/src/debug/daccess/enummem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
}


#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// WinRT stowed exception holds the (CCW)pointer to a managed exception object.
Expand Down Expand Up @@ -1431,11 +1431,26 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C
if (ccwPtr == NULL)
return S_OK;

OBJECTREF managedExceptionObject = NULL;

#ifdef FEATURE_COMINTEROP
// dump the managed exception object wrapped in CCW
// memory of the CCW object itself is dumped later by DacInstanceManager::DumpAllInstances
DacpCCWData ccwData;
GetCCWData(ccwPtr, &ccwData); // this call collects some memory implicitly
DumpManagedExcepObject(flags, OBJECTREF(TO_TADDR(ccwData.managedObject)));
managedExceptionObject = OBJECTREF(CLRDATA_ADDRESS_TO_TADDR(ccwData.managedObject));
#endif
#ifdef FEATURE_COMWRAPPERS
if (managedExceptionObject == NULL)
{
OBJECTREF wrappedObjAddress;
if (DACTryGetComWrappersObjectFromCCW(ccwPtr, &wrappedObjAddress) == S_OK)
{
managedExceptionObject = wrappedObjAddress;
}
}
#endif
DumpManagedExcepObject(flags, managedExceptionObject);

// dump memory of the 2nd slot in the CCW's vtable
// this is used in DACGetCCWFromAddress to identify if the passed in pointer is a valid CCW.
Expand All @@ -1450,7 +1465,8 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C

CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
(
ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR));
ReportMem(vTableAddress, sizeof(TADDR)); // Report the QI slot on the vtable for ComWrappers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Lets add #ifdef FEATURE_COMWRAPPERS for consistency

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't add an #ifdef in the parentheses because this is a macro invocation. I can refactor out just these two ReportMem calls so we can correctly ifdef the calls if you'd prefer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I wasn't thinking about that. Don't worry about it, the comment is already a pretty good marker and if we captured one extra pointer in the future in a config with this feature disabled its not a big deal : )

ReportMem(vTableAddress + sizeof(PBYTE) * TEAR_OFF_SLOT, sizeof(TADDR)); // Report the AddRef slot on the vtable for built-in CCWs
);

return S_OK;
Expand Down
71 changes: 71 additions & 0 deletions src/coreclr/src/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <comcallablewrapper.h>
#endif // FEATURE_COMINTEROP

#include <interoplibabi.h>

#ifndef TARGET_UNIX
// It is unfortunate having to include this header just to get the definition of GenericModeBlock
#include <msodw.h>
Expand Down Expand Up @@ -4065,6 +4067,75 @@ PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtab
}
#endif

#ifdef FEATURE_COMWRAPPERS
HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef)
{
if (ccwPtr == 0 || objRef == NULL)
return E_INVALIDARG;

SOSDacEnter();

// Read CCWs QI address and compare it to the managed object wrapper's implementation.
ULONG32 bytesRead = 0;
CLRDATA_ADDRESS vTableAddress = NULL;
IfFailGo(m_pTarget->ReadVirtual(ccwPtr, (PBYTE)&vTableAddress, sizeof(CLRDATA_ADDRESS), &bytesRead));
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
if (bytesRead != sizeof(CLRDATA_ADDRESS)
|| vTableAddress == NULL)
{
hr = S_FALSE;
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
goto ErrExit;
}

TADDR qiAddress = NULL;
IfFailGo(m_pTarget->ReadVirtual(vTableAddress, (PBYTE)&qiAddress, sizeof(TADDR), &bytesRead));
if (bytesRead != sizeof(TADDR)
|| qiAddress == NULL)
{
hr = S_FALSE;
goto ErrExit;
}


#ifdef TARGET_ARM
// clear the THUMB bit on qiAddress before comparing with known vtable entry
qiAddress &= ~THUMB_CODE;
#endif

if (qiAddress != GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface))
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
hr = S_FALSE;
goto ErrExit;
}

// Mask the "dispatch pointer" to get a double pointer to the ManagedObjectWrapper
CLRDATA_ADDRESS managedObjectWrapperPtrPtr = ccwPtr & InteropLib::ABI::DispatchThisPtrMask;

// Return ManagedObjectWrapper as an OBJECTHANDLE. (The OBJECTHANDLE is guaranteed to live at offset 0).
CLRDATA_ADDRESS managedObjectWrapperPtr;
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtrPtr, (PBYTE)&managedObjectWrapperPtr, sizeof(CLRDATA_ADDRESS), &bytesRead));
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
if (bytesRead != sizeof(CLRDATA_ADDRESS))
{
hr = S_FALSE;
goto ErrExit;
}

OBJECTHANDLE handle;
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtr, (PBYTE)&handle, sizeof(OBJECTHANDLE), &bytesRead));
if (bytesRead != sizeof(OBJECTHANDLE))
{
hr = S_FALSE;
goto ErrExit;
}

*objRef = ObjectFromHandle(handle);

SOSDacLeave();

return S_OK;

ErrExit: return hr;
}
#endif

HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData)
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/inc/daccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,9 @@ typedef struct _DacGlobals
ULONG fn__Unknown_AddRefSpecial;
ULONG fn__Unknown_AddRefInner;
#endif
#ifdef FEATURE_COMWRAPPERS
ULONG fn__ManagedObjectWrapper_QueryInterface;
#endif

// Vtable pointer values for all classes that must
// be instanted using vtable pointers as the identity.
Expand Down
27 changes: 16 additions & 11 deletions src/coreclr/src/interop/comwrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

#include "comwrappers.hpp"
#include <interoplibabi.h>
#include <interoplibimports.h>

#include <new> // placement new
Expand Down Expand Up @@ -47,8 +48,8 @@ namespace ABI
};
ABI_ASSERT(sizeof(ComInterfaceDispatch) == sizeof(void*));

const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
using InteropLib::ABI::DispatchAlignmentThisPtr;
using InteropLib::ABI::DispatchThisPtrMask;
ABI_ASSERT(sizeof(void*) < DispatchAlignmentThisPtr);

const intptr_t AlignmentThisPtrMaxPadding = DispatchAlignmentThisPtr - sizeof(void*);
Expand Down Expand Up @@ -179,17 +180,20 @@ namespace ABI
}
}

namespace
// ManagedObjectWrapper_QueryInterface needs to be visible outside of this compilation unit
// to support the DAC. See code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW for the
// usage in the DAC (look for the GetEEFuncEntryPoint call).
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
_In_ ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
{
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
_In_ ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
{
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
return wrapper->QueryInterface(riid, ppvObject);
}
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
return wrapper->QueryInterface(riid, ppvObject);
}

namespace
{
ULONG STDMETHODCALLTYPE ManagedObjectWrapper_AddRef(_In_ ABI::ComInterfaceDispatch* disp)
{
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
Expand Down Expand Up @@ -310,6 +314,7 @@ void ManagedObjectWrapper::GetIUnknownImpl(
*fpRelease = ManagedObjectWrapper_IUnknownImpl.Release;
}

// The logic here should match code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW in daccess/request.cpp
ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknown(_In_ IUnknown* pUnk)
{
_ASSERTE(pUnk != nullptr);
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/src/interop/inc/interoplibabi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include <stddef.h>

namespace InteropLib
{
namespace ABI
{
const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
}
}