diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs index 199b64bc8bb4b4..623ba1230cf41b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs @@ -100,21 +100,24 @@ private void SetTarget(object? target, ComInfo? comInfo) } } - internal object? Target => GCHandle.InternalGet(_weakHandle) ?? RehydrateTarget(); + internal object? Target => GCHandle.InternalGet(_weakHandle); - private object? RehydrateTarget() + internal nint WeakHandle => _weakHandle; + + internal T? RehydrateTarget() where T: class? { - object? target = null; + T? target = null; lock (this) { if (_comInfo != null) { - // check if the target is still null - target = GCHandle.InternalGet(_weakHandle); + // Check if the target is still null + target = Unsafe.As(GCHandle.InternalGet(_weakHandle)); if (target == null) { - // resolve and reset - target = _comInfo.ResolveTarget(); + // Resolve and reset. Perform runtime cast to catch bugs + // in COM interop where it rehydrates wrong type. + target = (T?)_comInfo.ResolveTarget(); if (target != null) GCHandle.InternalSet(_weakHandle, target); } @@ -147,16 +150,10 @@ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHand } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static object? GetTarget(nint taggedHandle) - { - Debug.Assert((taggedHandle & ComAwareBit) != 0); - return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)).Target; - } - - internal static nint GetWeakHandle(nint taggedHandle) + internal static ComAwareWeakReference GetFromTaggedReference(nint taggedHandle) { Debug.Assert((taggedHandle & ComAwareBit) != 0); - return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits))._weakHandle; + return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)); } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs index 567ac2efe53a73..bd6359e61dfb9e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs @@ -141,7 +141,9 @@ private T? Target #if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS if ((th & ComAwareBit) != 0) { - target = Unsafe.As(ComAwareWeakReference.GetTarget(th)); + ComAwareWeakReference cwr = ComAwareWeakReference.GetFromTaggedReference(th); + + target = Unsafe.As(cwr.Target) ?? cwr.RehydrateTarget(); // must keep the instance alive as long as we use the handle. GC.KeepAlive(this); diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs index bc06bc7805deeb..4d0a817f6e8b39 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs @@ -107,7 +107,7 @@ internal nint WeakHandle #if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS if ((th & ComAwareBit) != 0) - return ComAwareWeakReference.GetWeakHandle(th); + return ComAwareWeakReference.GetFromTaggedReference(th).WeakHandle; #endif return th & ~HandleTagBits; } @@ -166,7 +166,9 @@ public virtual object? Target #if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS if ((th & ComAwareBit) != 0) { - target = ComAwareWeakReference.GetTarget(th); + ComAwareWeakReference cwr = ComAwareWeakReference.GetFromTaggedReference(th); + + target = cwr.Target ?? cwr.RehydrateTarget(); // must keep the instance alive as long as we use the handle. GC.KeepAlive(this);