Closed rickbrew closed 9 months ago
It looks like this should also work:
fixed (IWICBitmap** ppBitmap = bitmap)
{
HRESULT hr = factory.Get()->CreateBitmap(..., ppBitmap);
...
}
ComPtr<T>
has a GetPinnableReference()
method that returns a ref T*
, which is what enables this.
Thanks Rick. I missed that during my own code reviews.
I am now auditing all of my ComPtr<T>
code to address this.
I use ComPtr<T>.Swap
in a few places to transfer ownership from a local variable to a newly constructed class, see https://github.com/0xC0000054/PSFilterPdn/blob/5446a012e59118d56bffd3ac51dcf1f918ce1bef/src/PSFilterShim/PSApi/Rendering/Internal/DeviceBitmapBrush.cs#L25C13-L25C13
Since the runtime initializes the ComPtr<T>
fields to 0/null when the class is created, calling Swap
causes the ref ComPtr<T>
constructor parameter to be set to null.
I'm seeing several places like this, but here's one example: https://github.com/0xC0000054/PSFilterPdn/blob/5446a012e59118d56bffd3ac51dcf1f918ce1bef/src/PSFilterShim/PSApi/Imaging/Internal/WICBitmapSurface.cs#L44
On the marked line, this is a GC hole. If the GC runs while
CreateBitmap()
is running, and if theWICBitmapSurface<TPixel>
instance happens to get moved, then the native method will write to wherethis.bitmap
was, which could be ... anything. The GC has no information to steer it away from doing this.ComPtr<T>.GetAddressOf()
should really be calledDangerousGetAddressOf()
. It usesUnsafe.AsPointer(ref this)
, which is only actually safe ifthis
(theComPtr<T>
) is pinned, or otherwise unmovable (e.g. on the stack, inside a native memory alloc, ...).You need to either pin
bitmap
, or just do what I do which is to bounce it through a stack local: