Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Robinson <arobins@microsoft.com>2020-12-10 02:17:18 +0300
committerGitHub <noreply@github.com>2020-12-10 02:17:18 +0300
commita7c31798739670fae93e962d1158439a83a118cf (patch)
treef4e9963506b89df416dd985f4fc2c5112e9b1c1a /src/coreclr/interop
parent84c817b89b0ab23f03435906cbcfeb2ebc852762 (diff)
Fix ComWrappers interaction with the IReferenceTracker interface (#45624)
* Fix ComWrappers' leak in aggregation scenario Convert Managed Object Wrapper (MOW) GC Handle from HNDTYPE_STRONG to HNDTYPE_REFCOUNTED. Add new CreateObjectFlags value to indicate aggregation during CreateObject scenario. This isn't reflected in the managed .NET 5 API surface area. In the ReferenceTracker scenario the ref count may never reach 0 so the MOW destructor needs to handle that case. The previous expectation for a null in the destructor was based on the STRONG handle logic. During aggregation scenarios involving ReferenceTracker, ownership of the inner is now the responsibility of the runtime. * ComWrappers tests
Diffstat (limited to 'src/coreclr/interop')
-rw-r--r--src/coreclr/interop/comwrappers.cpp215
-rw-r--r--src/coreclr/interop/comwrappers.hpp18
-rw-r--r--src/coreclr/interop/inc/interoplib.h18
-rw-r--r--src/coreclr/interop/interoplib.cpp92
-rw-r--r--src/coreclr/interop/trackerobjectmanager.cpp3
5 files changed, 220 insertions, 126 deletions
diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp
index a7d4db77698..f39472778cd 100644
--- a/src/coreclr/interop/comwrappers.cpp
+++ b/src/coreclr/interop/comwrappers.cpp
@@ -223,12 +223,10 @@ namespace
namespace
{
const int32_t TrackerRefShift = 32;
- const ULONGLONG TrackerRefCounter = ULONGLONG{ 1 } << TrackerRefShift;
- const ULONGLONG ComRefCounter = ULONGLONG{ 1 };
- const ULONGLONG TrackerRefZero = 0x0000000080000000;
+ const ULONGLONG TrackerRefCounter = ULONGLONG{ 1 } << TrackerRefShift;
+ const ULONGLONG DestroySentinel = 0x0000000080000000;
const ULONGLONG TrackerRefCountMask = 0xffffffff00000000;
const ULONGLONG ComRefCountMask = 0x000000007fffffff;
- const ULONGLONG RefCountMask = 0xffffffff7fffffff;
constexpr ULONG GetTrackerCount(_In_ ULONGLONG c)
{
@@ -419,11 +417,29 @@ HRESULT ManagedObjectWrapper::Create(
void ManagedObjectWrapper::Destroy(_In_ ManagedObjectWrapper* wrapper)
{
_ASSERTE(wrapper != nullptr);
+ _ASSERTE(GetComCount(wrapper->_refCount) == 0);
- // Manually trigger the destructor since placement
- // new was used to allocate the object.
- wrapper->~ManagedObjectWrapper();
- InteropLibImports::MemFree(wrapper, AllocScenario::ManagedObjectWrapper);
+ // Attempt to set the destroyed bit.
+ LONGLONG refCount;
+ LONGLONG prev;
+ do
+ {
+ prev = wrapper->_refCount;
+ refCount = prev | DestroySentinel;
+ } while (::InterlockedCompareExchange64(&wrapper->_refCount, refCount, prev) != prev);
+
+ // The destroy sentinel represents the bit that indicates the wrapper
+ // should be destroyed. Since the reference count field (64-bit) holds
+ // two counters we rely on the singular sentinal value - no other bits
+ // in the 64-bit counter are set. If there are outstanding bits set it
+ // indicates there are still outstanding references.
+ if (refCount == DestroySentinel)
+ {
+ // Manually trigger the destructor since placement
+ // new was used to allocate the object.
+ wrapper->~ManagedObjectWrapper();
+ InteropLibImports::MemFree(wrapper, AllocScenario::ManagedObjectWrapper);
+ }
}
ManagedObjectWrapper::ManagedObjectWrapper(
@@ -449,48 +465,9 @@ ManagedObjectWrapper::ManagedObjectWrapper(
ManagedObjectWrapper::~ManagedObjectWrapper()
{
- // If the target isn't null, then a managed object
- // is going to leak.
- _ASSERTE(Target == nullptr);
-}
-
-ULONGLONG ManagedObjectWrapper::UniversalRelease(_In_ ULONGLONG dec)
-{
- OBJECTHANDLE local = Target;
-
- LONGLONG refCount;
- if (dec == ComRefCounter)
- {
- _ASSERTE(dec == 1);
- refCount = ::InterlockedDecrement64(&_refCount);
- }
- else
- {
- _ASSERTE(dec == TrackerRefCounter);
- LONGLONG prev;
- do
- {
- prev = _refCount;
- refCount = prev - dec;
- } while (::InterlockedCompareExchange64(&_refCount, refCount, prev) != prev);
- }
-
- // It is possible that a target wasn't set during an
- // attempt to reactive the wrapper.
- if ((RefCountMask & refCount) == 0 && local != nullptr)
- {
- _ASSERTE(!IsSet(CreateComInterfaceFlagsEx::IsPegged));
- _ASSERTE(refCount == TrackerRefZero || refCount == 0);
-
- // Attempt to reset the target if its current value is the same.
- // It is possible the wrapper is in the middle of being reactivated.
- (void)TrySetObjectHandle(nullptr, local);
-
- // Tell the runtime to delete the managed object instance handle.
- InteropLibImports::DeleteObjectInstanceHandle(local);
- }
-
- return refCount;
+ // If the target isn't null, then release it.
+ if (Target != nullptr)
+ InteropLibImports::DeleteObjectInstanceHandle(Target);
}
void* ManagedObjectWrapper::AsRuntimeDefined(_In_ REFIID riid)
@@ -551,16 +528,18 @@ void ManagedObjectWrapper::ResetFlag(_In_ CreateComInterfaceFlagsEx flag)
::InterlockedAnd((LONG*)&_flags, resetMask);
}
-ULONG ManagedObjectWrapper::IsActiveAddRef()
+bool ManagedObjectWrapper::IsRooted() const
{
- ULONG count = GetComCount(::InterlockedIncrement64(&_refCount));
- if (count == 1)
+ bool rooted = GetComCount(_refCount) > 0;
+ if (!rooted)
{
- // Ensure the current target is null.
- ::InterlockedExchangePointer(&Target, nullptr);
+ // Only consider tracker ref count to be a "strong" ref count if it is pegged and alive.
+ rooted = (GetTrackerCount(_refCount) > 0)
+ && (IsSet(CreateComInterfaceFlagsEx::IsPegged)
+ || InteropLibImports::GetGlobalPeggingState());
}
- return count;
+ return rooted;
}
ULONG ManagedObjectWrapper::AddRefFromReferenceTracker()
@@ -578,7 +557,29 @@ ULONG ManagedObjectWrapper::AddRefFromReferenceTracker()
ULONG ManagedObjectWrapper::ReleaseFromReferenceTracker()
{
- return GetTrackerCount(UniversalRelease(TrackerRefCounter));
+ if (GetTrackerCount(_refCount) == 0)
+ {
+ _ASSERTE(!"Over release of MOW - ReferenceTracker");
+ return (ULONG)-1;
+ }
+
+ LONGLONG refCount;
+ LONGLONG prev;
+ do
+ {
+ prev = _refCount;
+ refCount = prev - TrackerRefCounter;
+ } while (::InterlockedCompareExchange64(&_refCount, refCount, prev) != prev);
+
+ // If we observe the destroy sentinel, then this release
+ // must destroy the wrapper.
+ if (refCount == DestroySentinel)
+ {
+ _ASSERTE(!IsSet(CreateComInterfaceFlagsEx::IsPegged));
+ Destroy(this);
+ }
+
+ return GetTrackerCount(refCount);
}
HRESULT ManagedObjectWrapper::Peg()
@@ -652,12 +653,20 @@ HRESULT ManagedObjectWrapper::QueryInterface(
ULONG ManagedObjectWrapper::AddRef(void)
{
+ _ASSERTE((_refCount & DestroySentinel) == 0);
return GetComCount(::InterlockedIncrement64(&_refCount));
}
ULONG ManagedObjectWrapper::Release(void)
{
- return GetComCount(UniversalRelease(ComRefCounter));
+ _ASSERTE((_refCount & DestroySentinel) == 0);
+ if (GetComCount(_refCount) == 0)
+ {
+ _ASSERTE(!"Over release of MOW - COM");
+ return (ULONG)-1;
+ }
+
+ return GetComCount(::InterlockedDecrement64(&_refCount));
}
namespace
@@ -684,12 +693,19 @@ NativeObjectWrapperContext* NativeObjectWrapperContext::MapFromRuntimeContext(_I
HRESULT NativeObjectWrapperContext::Create(
_In_ IUnknown* external,
+ _In_opt_ IUnknown* inner,
_In_ InteropLib::Com::CreateObjectFlags flags,
_In_ size_t runtimeContextSize,
_Outptr_ NativeObjectWrapperContext** context)
{
_ASSERTE(external != nullptr && context != nullptr);
+ // Aggregated inners are only currently supported for Aggregated
+ // scenarios involving IReferenceTracker.
+ _ASSERTE(inner == nullptr
+ || ((flags & InteropLib::Com::CreateObjectFlags_TrackerObject)
+ && (flags & InteropLib::Com::CreateObjectFlags_Aggregated)));
+
HRESULT hr;
ComHolder<IReferenceTracker> trackerObject;
@@ -710,7 +726,7 @@ HRESULT NativeObjectWrapperContext::Create(
// Contract specifically requires zeroing out runtime context.
::memset(runtimeContext, 0, runtimeContextSize);
- NativeObjectWrapperContext* contextLocal = new (cxtMem) NativeObjectWrapperContext{ runtimeContext, trackerObject };
+ NativeObjectWrapperContext* contextLocal = new (cxtMem) NativeObjectWrapperContext{ runtimeContext, trackerObject, inner };
if (trackerObject != nullptr)
{
@@ -722,6 +738,13 @@ HRESULT NativeObjectWrapperContext::Create(
Destroy(contextLocal);
return hr;
}
+
+ // Aggregation with a tracker object must be "cleaned up".
+ if (flags & InteropLib::Com::CreateObjectFlags_Aggregated)
+ {
+ _ASSERTE(inner != nullptr);
+ contextLocal->HandleReferenceTrackerAggregation();
+ }
}
*context = contextLocal;
@@ -732,21 +755,48 @@ void NativeObjectWrapperContext::Destroy(_In_ NativeObjectWrapperContext* wrappe
{
_ASSERTE(wrapper != nullptr);
+ // Check if the tracker object manager should be informed prior to being destroyed.
+ IReferenceTracker* trackerMaybe = wrapper->GetReferenceTracker();
+ if (trackerMaybe != nullptr)
+ {
+ // We only call this during a GC so ignore the failure as
+ // there is no way we can handle it at this point.
+ HRESULT hr = TrackerObjectManager::BeforeWrapperDestroyed(trackerMaybe);
+ _ASSERTE(SUCCEEDED(hr));
+ (void)hr;
+ }
+
// Manually trigger the destructor since placement
// new was used to allocate the object.
wrapper->~NativeObjectWrapperContext();
InteropLibImports::MemFree(wrapper, AllocScenario::NativeObjectWrapper);
}
-NativeObjectWrapperContext::NativeObjectWrapperContext(_In_ void* runtimeContext, _In_opt_ IReferenceTracker* trackerObject)
+namespace
+{
+ // State ownership mechanism.
+ enum : int
+ {
+ TrackerObjectState_NotSet = 0,
+ TrackerObjectState_SetNoRelease = 1,
+ TrackerObjectState_SetForRelease = 2,
+ };
+}
+
+NativeObjectWrapperContext::NativeObjectWrapperContext(
+ _In_ void* runtimeContext,
+ _In_opt_ IReferenceTracker* trackerObject,
+ _In_opt_ IUnknown* nativeObjectAsInner)
: _trackerObject{ trackerObject }
, _runtimeContext{ runtimeContext }
- , _isValidTracker{ (trackerObject != nullptr ? TRUE : FALSE) }
+ , _trackerObjectDisconnected{ FALSE }
+ , _trackerObjectState{ (trackerObject == nullptr ? TrackerObjectState_NotSet : TrackerObjectState_SetForRelease) }
+ , _nativeObjectAsInner{ nativeObjectAsInner }
#ifdef _DEBUG
, _sentinel{ LiveContextSentinel }
#endif
{
- if (_isValidTracker == TRUE)
+ if (_trackerObjectState == TrackerObjectState_SetForRelease)
(void)_trackerObject->AddRef();
}
@@ -754,6 +804,10 @@ NativeObjectWrapperContext::~NativeObjectWrapperContext()
{
DisconnectTracker();
+ // If the inner was supplied, we need to release our reference.
+ if (_nativeObjectAsInner != nullptr)
+ (void)_nativeObjectAsInner->Release();
+
#ifdef _DEBUG
_sentinel = DeadContextSentinel;
#endif
@@ -766,12 +820,43 @@ void* NativeObjectWrapperContext::GetRuntimeContext() const noexcept
IReferenceTracker* NativeObjectWrapperContext::GetReferenceTracker() const noexcept
{
- return ((_isValidTracker == TRUE) ? _trackerObject : nullptr);
+ return ((_trackerObjectState == TrackerObjectState_NotSet) ? nullptr : _trackerObject);
}
+// See TrackerObjectManager::AfterWrapperCreated() for AddRefFromTrackerSource() usage.
+// See NativeObjectWrapperContext::HandleReferenceTrackerAggregation() for additional
+// cleanup logistics.
void NativeObjectWrapperContext::DisconnectTracker() noexcept
{
- // Attempt to disconnect from the tracker.
- if (TRUE == ::InterlockedCompareExchange((LONG*)&_isValidTracker, FALSE, TRUE))
+ // Return if already disconnected or the tracker isn't set.
+ if (FALSE != ::InterlockedCompareExchange((LONG*)&_trackerObjectDisconnected, TRUE, FALSE)
+ || _trackerObjectState == TrackerObjectState_NotSet)
+ {
+ return;
+ }
+
+ _ASSERTE(_trackerObject != nullptr);
+
+ // Always release the tracker source during a disconnect.
+ // This to account for the implied IUnknown ownership by the runtime.
+ (void)_trackerObject->ReleaseFromTrackerSource(); // IUnknown
+
+ // Disconnect from the tracker.
+ if (_trackerObjectState == TrackerObjectState_SetForRelease)
+ {
+ (void)_trackerObject->ReleaseFromTrackerSource(); // IReferenceTracker
(void)_trackerObject->Release();
+ }
+}
+
+void NativeObjectWrapperContext::HandleReferenceTrackerAggregation() noexcept
+{
+ _ASSERTE(_trackerObjectState == TrackerObjectState_SetForRelease && _trackerObject != nullptr);
+
+ // Aggregation with an IReferenceTracker instance creates an extra AddRef()
+ // on the outer (e.g. MOW) so we clean up that issue here.
+ _trackerObjectState = TrackerObjectState_SetNoRelease;
+
+ (void)_trackerObject->ReleaseFromTrackerSource(); // IReferenceTracker
+ (void)_trackerObject->Release();
}
diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp
index 3ae91d8a88c..e4d849a5625 100644
--- a/src/coreclr/interop/comwrappers.hpp
+++ b/src/coreclr/interop/comwrappers.hpp
@@ -82,10 +82,6 @@ private:
~ManagedObjectWrapper();
- // Represents a single implementation of how to release
- // the wrapper. Supplied with a decrementing value.
- ULONGLONG UniversalRelease(_In_ ULONGLONG dec);
-
// Query the runtime defined tables.
void* AsRuntimeDefined(_In_ REFIID riid);
@@ -102,8 +98,8 @@ public:
void SetFlag(_In_ CreateComInterfaceFlagsEx flag);
void ResetFlag(_In_ CreateComInterfaceFlagsEx flag);
- // Used while validating wrapper is active.
- ULONG IsActiveAddRef();
+ // Indicate if the wrapper should be considered a GC root.
+ bool IsRooted() const;
public: // IReferenceTrackerTarget
ULONG AddRefFromReferenceTracker();
@@ -139,7 +135,9 @@ class NativeObjectWrapperContext
{
IReferenceTracker* _trackerObject;
void* _runtimeContext;
- Volatile<BOOL> _isValidTracker;
+ Volatile<BOOL> _trackerObjectDisconnected;
+ int _trackerObjectState;
+ IUnknown* _nativeObjectAsInner;
#ifdef _DEBUG
size_t _sentinel;
@@ -151,6 +149,7 @@ public: // static
// Create a NativeObjectWrapperContext instance
static HRESULT NativeObjectWrapperContext::Create(
_In_ IUnknown* external,
+ _In_opt_ IUnknown* nativeObjectAsInner,
_In_ InteropLib::Com::CreateObjectFlags flags,
_In_ size_t runtimeContextSize,
_Outptr_ NativeObjectWrapperContext** context);
@@ -159,7 +158,7 @@ public: // static
static void Destroy(_In_ NativeObjectWrapperContext* wrapper);
private:
- NativeObjectWrapperContext(_In_ void* runtimeContext, _In_opt_ IReferenceTracker* trackerObject);
+ NativeObjectWrapperContext(_In_ void* runtimeContext, _In_opt_ IReferenceTracker* trackerObject, _In_opt_ IUnknown* nativeObjectAsInner);
~NativeObjectWrapperContext();
public:
@@ -171,6 +170,9 @@ public:
// Disconnect reference tracker instance.
void DisconnectTracker() noexcept;
+
+private:
+ void HandleReferenceTrackerAggregation() noexcept;
};
// Manage native object wrappers that support IReferenceTracker.
diff --git a/src/coreclr/interop/inc/interoplib.h b/src/coreclr/interop/inc/interoplib.h
index a1f32b99ecd..39ceadfbb80 100644
--- a/src/coreclr/interop/inc/interoplib.h
+++ b/src/coreclr/interop/inc/interoplib.h
@@ -38,11 +38,8 @@ namespace InteropLib
// Destroy the supplied wrapper
void DestroyWrapperForObject(_In_ void* wrapper) noexcept;
- // Check if a wrapper is active.
- HRESULT IsActiveWrapper(_In_ IUnknown* wrapper) noexcept;
-
- // Reactivate the supplied wrapper.
- HRESULT ReactivateWrapper(_In_ IUnknown* wrapper, _In_ InteropLib::OBJECTHANDLE handle) noexcept;
+ // Check if a wrapper is considered a GC root.
+ HRESULT IsWrapperRooted(_In_ IUnknown* wrapper) noexcept;
// Get the object for the supplied wrapper
HRESULT GetObjectForWrapper(_In_ IUnknown* wrapper, _Outptr_result_maybenull_ OBJECTHANDLE* object) noexcept;
@@ -58,6 +55,9 @@ namespace InteropLib
// See https://docs.microsoft.com/windows/win32/api/windows.ui.xaml.hosting.referencetracker/
// for details.
bool FromTrackerRuntime;
+
+ // The supplied external object is wrapping a managed object.
+ bool ManagedObjectWrapper;
};
// See CreateObjectFlags in ComWrappers.cs
@@ -66,13 +66,21 @@ namespace InteropLib
CreateObjectFlags_None = 0,
CreateObjectFlags_TrackerObject = 1,
CreateObjectFlags_UniqueInstance = 2,
+ CreateObjectFlags_Aggregated = 4,
};
+ // Get the true identity for the supplied IUnknown.
+ HRESULT GetIdentityForCreateWrapperForExternal(
+ _In_ IUnknown* external,
+ _In_ enum CreateObjectFlags flags,
+ _Outptr_ IUnknown** identity) noexcept;
+
// Allocate a wrapper context for an external object.
// The runtime supplies the external object, flags, and a memory
// request in order to bring the object into the runtime.
HRESULT CreateWrapperForExternal(
_In_ IUnknown* external,
+ _In_opt_ IUnknown* inner,
_In_ enum CreateObjectFlags flags,
_In_ size_t contextSize,
_Out_ ExternalWrapperResult* result) noexcept;
diff --git a/src/coreclr/interop/interoplib.cpp b/src/coreclr/interop/interoplib.cpp
index f730817dea3..9aff8c2bb33 100644
--- a/src/coreclr/interop/interoplib.cpp
+++ b/src/coreclr/interop/interoplib.cpp
@@ -54,53 +54,26 @@ namespace InteropLib
ManagedObjectWrapper::Destroy(wrapper);
}
- HRESULT IsActiveWrapper(_In_ IUnknown* wrapperMaybe) noexcept
+ HRESULT IsWrapperRooted(_In_ IUnknown* wrapperMaybe) noexcept
{
ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknown(wrapperMaybe);
if (wrapper == nullptr)
return E_INVALIDARG;
- ULONG count = wrapper->IsActiveAddRef();
- if (count == 1 || wrapper->Target == nullptr)
- {
- // The wrapper isn't active.
- (void)wrapper->Release();
- return S_FALSE;
- }
-
- return S_OK;
- }
-
- HRESULT ReactivateWrapper(_In_ IUnknown* wrapperMaybe, _In_ OBJECTHANDLE handle) noexcept
- {
- ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknown(wrapperMaybe);
- if (wrapper == nullptr || handle == nullptr)
- return E_INVALIDARG;
-
- // Take an AddRef() as an indication of ownership.
- (void)wrapper->AddRef();
-
- // If setting this object handle fails, then the race
- // was lost and we will cleanup the handle.
- if (!wrapper->TrySetObjectHandle(handle))
- InteropLibImports::DeleteObjectInstanceHandle(handle);
-
- return S_OK;
+ return wrapper->IsRooted() ? S_OK : S_FALSE;
}
HRESULT GetObjectForWrapper(_In_ IUnknown* wrapper, _Outptr_result_maybenull_ OBJECTHANDLE* object) noexcept
{
- if (object == nullptr)
- return E_POINTER;
-
+ _ASSERTE(wrapper != nullptr && object != nullptr);
*object = nullptr;
- HRESULT hr = IsActiveWrapper(wrapper);
- if (hr != S_OK)
- return hr;
-
+ // Attempt to get the managed object wrapper.
ManagedObjectWrapper *mow = ManagedObjectWrapper::MapFromIUnknown(wrapper);
- _ASSERTE(mow != nullptr);
+ if (mow == nullptr)
+ return E_INVALIDARG;
+
+ (void)mow->AddRef();
*object = mow->Target;
return S_OK;
@@ -125,8 +98,43 @@ namespace InteropLib
return wrapper->IsSet(CreateComInterfaceFlagsEx::IsComActivated) ? S_OK : S_FALSE;
}
+ HRESULT GetIdentityForCreateWrapperForExternal(
+ _In_ IUnknown* external,
+ _In_ enum CreateObjectFlags flags,
+ _Outptr_ IUnknown** identity) noexcept
+ {
+ _ASSERTE(external != nullptr && identity != nullptr);
+
+ IUnknown* checkForIdentity = external;
+
+ // Check if the flags indicate we are creating
+ // an object for an external IReferenceTracker instance
+ // that we are aggregating with.
+ bool refTrackerInnerScenario = (flags & CreateObjectFlags_TrackerObject)
+ && (flags & CreateObjectFlags_Aggregated);
+
+ ComHolder<IReferenceTracker> trackerObject;
+ if (refTrackerInnerScenario)
+ {
+ // We are checking the supplied external value
+ // for IReferenceTracker since in .NET 5 this could
+ // actually be the inner and we want the true identity
+ // not the inner . This is a trick since the only way
+ // to get identity from an inner is through a non-IUnknown
+ // interface QI. Once we have the IReferenceTracker
+ // instance we can be sure the QI for IUnknown will really
+ // be the true identity.
+ HRESULT hr = external->QueryInterface(&trackerObject);
+ if (SUCCEEDED(hr))
+ checkForIdentity = trackerObject.p;
+ }
+
+ return checkForIdentity->QueryInterface(identity);
+ }
+
HRESULT CreateWrapperForExternal(
_In_ IUnknown* external,
+ _In_opt_ IUnknown* inner,
_In_ enum CreateObjectFlags flags,
_In_ size_t contextSize,
_Out_ ExternalWrapperResult* result) noexcept
@@ -136,10 +144,11 @@ namespace InteropLib
HRESULT hr;
NativeObjectWrapperContext* wrapperContext;
- RETURN_IF_FAILED(NativeObjectWrapperContext::Create(external, flags, contextSize, &wrapperContext));
+ RETURN_IF_FAILED(NativeObjectWrapperContext::Create(external, inner, flags, contextSize, &wrapperContext));
result->Context = wrapperContext->GetRuntimeContext();
result->FromTrackerRuntime = (wrapperContext->GetReferenceTracker() != nullptr);
+ result->ManagedObjectWrapper = (ManagedObjectWrapper::MapFromIUnknown(external) != nullptr);
return S_OK;
}
@@ -150,17 +159,6 @@ namespace InteropLib
// A caller should not be destroying a context without knowing if the context is valid.
_ASSERTE(context != nullptr);
- // Check if the tracker object manager should be informed prior to being destroyed.
- IReferenceTracker* trackerMaybe = context->GetReferenceTracker();
- if (trackerMaybe != nullptr)
- {
- // We only call this during a GC so ignore the failure as
- // there is no way we can handle it at this point.
- HRESULT hr = TrackerObjectManager::BeforeWrapperDestroyed(trackerMaybe);
- _ASSERTE(SUCCEEDED(hr));
- (void)hr;
- }
-
NativeObjectWrapperContext::Destroy(context);
}
diff --git a/src/coreclr/interop/trackerobjectmanager.cpp b/src/coreclr/interop/trackerobjectmanager.cpp
index 91cc894c0ee..f205484d3b0 100644
--- a/src/coreclr/interop/trackerobjectmanager.cpp
+++ b/src/coreclr/interop/trackerobjectmanager.cpp
@@ -296,7 +296,8 @@ HRESULT TrackerObjectManager::AfterWrapperCreated(_In_ IReferenceTracker* obj)
// Send out AddRefFromTrackerSource callbacks to notify tracker runtime we've done AddRef()
// for certain interfaces. We should do this *after* we made a AddRef() because we should never
// be in a state where report refs > actual refs
- RETURN_IF_FAILED(obj->AddRefFromTrackerSource());
+ RETURN_IF_FAILED(obj->AddRefFromTrackerSource()); // IUnknown
+ RETURN_IF_FAILED(obj->AddRefFromTrackerSource()); // IReferenceTracker
return S_OK;
}