Skip to content

Commit a3c21b9

Browse files
authored
Add GC.KeepAlive to COM paths in WeakReference (#88537)
Omission was noticed by @AustinWise. I reproed the failure and this fix for it on linux-x64. Fixes #81362
1 parent 82bf906 commit a3c21b9

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ public void SetTarget(T target)
110110
if ((th & ComAwareBit) != 0 || comInfo != null)
111111
{
112112
ComAwareWeakReference.SetTarget(ref _taggedHandle, target, comInfo);
113+
114+
// must keep the instance alive as long as we use the handle.
115+
GC.KeepAlive(this);
116+
113117
return;
114118
}
115119
#endif
@@ -133,13 +137,22 @@ private T? Target
133137
if (th == 0)
134138
return default;
135139

140+
T? target;
141+
136142
#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
137143
if ((th & ComAwareBit) != 0)
138-
return Unsafe.As<T?>(ComAwareWeakReference.GetTarget(th));
144+
{
145+
target = Unsafe.As<T?>(ComAwareWeakReference.GetTarget(th));
146+
147+
// must keep the instance alive as long as we use the handle.
148+
GC.KeepAlive(this);
149+
150+
return target;
151+
}
139152
#endif
140153

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

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

src/libraries/System.Private.CoreLib/src/System/WeakReference.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,22 @@ public virtual object? Target
157157
if (th == 0)
158158
return default;
159159

160+
object? target;
161+
160162
#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
161163
if ((th & ComAwareBit) != 0)
162-
return ComAwareWeakReference.GetTarget(th);
164+
{
165+
target = ComAwareWeakReference.GetTarget(th);
166+
167+
// must keep the instance alive as long as we use the handle.
168+
GC.KeepAlive(this);
169+
170+
return target;
171+
}
163172
#endif
164173

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

168177
// must keep the instance alive as long as we use the handle.
169178
GC.KeepAlive(this);
@@ -186,6 +195,10 @@ public virtual object? Target
186195
if ((th & ComAwareBit) != 0 || comInfo != null)
187196
{
188197
ComAwareWeakReference.SetTarget(ref _taggedHandle, value, comInfo);
198+
199+
// must keep the instance alive as long as we use the handle.
200+
GC.KeepAlive(this);
201+
189202
return;
190203
}
191204
#endif

src/tests/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
<!-- Registers global instances of ComWrappers -->
55
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
7-
<!-- Temporarily disabled due to https://github.com/dotnet/runtime/issues/81362 -->
8-
<GCStressIncompatible>true</GCStressIncompatible>
97
</PropertyGroup>
108
<ItemGroup>
119
<Compile Include="WeakReferenceTest.cs" />

0 commit comments

Comments
 (0)