Skip to content

Commit bc8706e

Browse files
Fix referenceTracker scenarios where we use the result of QI on failure (#2305)
* Fix QI not setting to null on failure * Minor nits --------- Co-authored-by: Sergio Pedri <sergio0694@live.com>
1 parent 5db4f45 commit bc8706e

1 file changed

Lines changed: 23 additions & 5 deletions

File tree

src/WinRT.Runtime2/InteropServices/ObjectReference/WindowsRuntimeObjectReference.Initialization.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,15 @@ internal static WindowsRuntimeObjectReference InitializeFromManagedTypeUnsafe(
108108
// will have the 'IReferenceTracker' implementation. Otherwise, the new instance will be used. Since the
109109
// inner was composed, it should answer immediately without going through the outer. Either way, the
110110
// reference count will go to the new instance.
111-
_ = IUnknownVftbl.QueryInterfaceUnsafe(externalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
111+
HRESULT isReferenceTracker = IUnknownVftbl.QueryInterfaceUnsafe(externalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
112+
113+
// We have seen scenarios where 'QueryInterface' is not set to 'null' on failure (for instance, both UWP XAML
114+
// and WinUI 3 objects don't do this), so if the call failed we manually set the resulting pointer to 'null'.
115+
// This allows the following code to rely on the pointer value to determine how to handle reference tracking.
116+
if (isReferenceTracker.Failed)
117+
{
118+
referenceTracker = null;
119+
}
112120

113121
// Determine the flags needed for the native object wrapper (ie. RCW) creation.
114122
// These are the ones we'll pass to 'ComWrappers' to register the new object.
@@ -296,9 +304,9 @@ internal static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(vo
296304
Marshal.ThrowExceptionForHR(isFreeThreaded);
297305

298306
// Try to resolve an 'IReferenceTracker' pointer (see detailed notes above)
299-
_ = IUnknownVftbl.QueryInterfaceUnsafe(externalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
307+
HRESULT isReferenceTracker = IUnknownVftbl.QueryInterfaceUnsafe(externalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
300308

301-
if (referenceTracker is not null)
309+
if (isReferenceTracker.Succeeded)
302310
{
303311
// If we have a reference tracker, we should report an 'AddRef' on it,
304312
// as we're wrapping the native object in a managed object reference.
@@ -309,6 +317,11 @@ internal static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(vo
309317
// This matches the handling of non aggregation scenarios above.
310318
_ = IUnknownVftbl.ReleaseUnsafe(referenceTracker);
311319
}
320+
else
321+
{
322+
// Ensure the 'IReferenceTracker' pointer is 'null' in case of failure (see notes above)
323+
referenceTracker = null;
324+
}
312325

313326
// We're going to store the input object, so increment its ref count
314327
_ = IUnknownVftbl.AddRefUnsafe(externalComObject);
@@ -351,15 +364,20 @@ private static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(ref
351364
}
352365

353366
// Try to resolve an 'IReferenceTracker' pointer (see detailed notes above)
354-
_ = IUnknownVftbl.QueryInterfaceUnsafe(acquiredExternalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
367+
HRESULT isReferenceTracker = IUnknownVftbl.QueryInterfaceUnsafe(acquiredExternalComObject, in WellKnownWindowsInterfaceIIDs.IID_IReferenceTracker, out void* referenceTracker);
355368

356369
// If we resolved a reference tracker, set it up (see notes above)
357-
if (referenceTracker is not null)
370+
if (isReferenceTracker.Succeeded)
358371
{
359372
_ = IReferenceTrackerVftbl.AddRefFromTrackerSourceUnsafe(referenceTracker);
360373

361374
_ = IUnknownVftbl.ReleaseUnsafe(referenceTracker);
362375
}
376+
else
377+
{
378+
// Ensure the 'IReferenceTracker' pointer is 'null' in case of failure (see notes above)
379+
referenceTracker = null;
380+
}
363381

364382
// Special case for free-threaded object references (see notes above)
365383
if (isFreeThreaded == WellKnownErrorCodes.S_OK)

0 commit comments

Comments
 (0)