Skip to content

Commit

Permalink
Add GC.KeepAlive to COM paths in WeakReference (#88537)
Browse files Browse the repository at this point in the history
Omission was noticed by @AustinWise. I reproed the failure and this fix for it on linux-x64.

Fixes #81362
  • Loading branch information
markples authored Jul 12, 2023
1 parent 82bf906 commit a3c21b9
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
17 changes: 15 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public void SetTarget(T target)
if ((th & ComAwareBit) != 0 || comInfo != null)
{
ComAwareWeakReference.SetTarget(ref _taggedHandle, target, comInfo);

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);

return;
}
#endif
Expand All @@ -133,13 +137,22 @@ private T? Target
if (th == 0)
return default;

T? target;

#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
if ((th & ComAwareBit) != 0)
return Unsafe.As<T?>(ComAwareWeakReference.GetTarget(th));
{
target = Unsafe.As<T?>(ComAwareWeakReference.GetTarget(th));

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);

return target;
}
#endif

// unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive
T? target = Unsafe.As<T?>(GCHandle.InternalGet(th));
target = Unsafe.As<T?>(GCHandle.InternalGet(th));

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
Expand Down
17 changes: 15 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/WeakReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,22 @@ public virtual object? Target
if (th == 0)
return default;

object? target;

#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
if ((th & ComAwareBit) != 0)
return ComAwareWeakReference.GetTarget(th);
{
target = ComAwareWeakReference.GetTarget(th);

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);

return target;
}
#endif

// unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive
object? target = GCHandle.InternalGet(th);
target = GCHandle.InternalGet(th);

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
Expand All @@ -186,6 +195,10 @@ public virtual object? Target
if ((th & ComAwareBit) != 0 || comInfo != null)
{
ComAwareWeakReference.SetTarget(ref _taggedHandle, value, comInfo);

// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);

return;
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
<!-- Registers global instances of ComWrappers -->
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Temporarily disabled due to https://github.com/dotnet/runtime/issues/81362 -->
<GCStressIncompatible>true</GCStressIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="WeakReferenceTest.cs" />
Expand Down

0 comments on commit a3c21b9

Please sign in to comment.