You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Managed arrays are unpinned when the original Mat is disposed or finalized. Captured submat data pointers are not updated on subsequent GC compaction, causing AccessViolationExceptions. Mats created by the following constructors are affected:
This is caused by the GCHandle DataHandle lifetime management of the DisposableObject parent class and affects all Mat instances which are a submat of the original Mat once the original is disposed or finalized. Both problematic constructors call the DisposableObject.AllocGCHandle method which sets the DataHandle property of the parent DisposableObject class. However, upon either disposal or finalization the DisposeUnmanaged() method is called, which runs the following code to dispose of the GCHandle:
Thus, the source array is unpinned even when submats with references to the current array location are present. The GC may then move the array, causing incorrect memory access or an AccessViolationException when using the captured submatrices.
Environment
All environments
What did you do when you faced the problem?
We are currently using NET8 [UnsafeAccessor] to query the DataHandle.IsAllocated property and create a copy whenever we see this, but this isn't a valid solution. The array GCHandle needs a proper lifetime management and reference counting implementation. To avoid affecting other classes descendant from DisposableObject, we could remove the GCHandle management by the base class and manage it in the Mat class itself. Since this only affects submatrices, a sample solution could be:
Manage the reference count somehow. Done in a helper class below.
/// <summary>/// Pins an array and unpins it when all references are released./// </summary>internalclassArrayPinningLifetime:IDisposable{privateGCHandle_handle;privateint_refCount;publicArrayPinningLifetime(Arrayarray){_handle=GCHandle.Alloc(array,GCHandleType.Pinned);}publicIntPtrData=>_handle.IsAllocated?_handle.AddrOfPinnedObject():thrownewObjectDisposedException(nameof(ArrayPinningLifetime));publicArrayPinningLifetimeRef(){Interlocked.Increment(ref_refCount);returnthis;}publicvoidDispose(){if(Interlocked.Decrement(ref_refCount)!=0||!_handle.IsAllocated){return;}_handle.Free();GC.SuppressFinalize(this);}~ArrayPinningLifetime(){if(_handle.IsAllocated){_handle.Free();}}}
Update the Mat class to contain the reference counting logic and maintain a reference for all submatrices.
publicclassMat{
...privateArrayPinningLifetime?_pinLifetime;publicMatSubMat(introwStart,introwEnd,intcolStart,intcolEnd){ThrowIfDisposed();NativeMethods.HandleException(NativeMethods.core_Mat_subMat1(ptr,rowStart,rowEnd,colStart,colEnd,outvarret));GC.KeepAlive(this);varretVal=newMat(ret);// Keep the array pinned as long as the Mat is aliveretVal._pinLifetime=_pinLifetime?.Ref();returnretVal;}protectedoverridevoidDisposeManaged()=>_pinLifetime.Dispose();}
The text was updated successfully, but these errors were encountered:
Summary of your issue
Managed arrays are unpinned when the original
Mat
is disposed or finalized. Captured submat data pointers are not updated on subsequent GC compaction, causingAccessViolationException
s.Mat
s created by the following constructors are affected:This is caused by the
GCHandle DataHandle
lifetime management of theDisposableObject
parent class and affects allMat
instances which are a submat of the originalMat
once the original is disposed or finalized. Both problematic constructors call theDisposableObject.AllocGCHandle
method which sets theDataHandle
property of the parentDisposableObject
class. However, upon either disposal or finalization theDisposeUnmanaged()
method is called, which runs the following code to dispose of theGCHandle
:Thus, the source array is unpinned even when submats with references to the current array location are present. The GC may then move the array, causing incorrect memory access or an
AccessViolationException
when using the captured submatrices.Environment
All environments
What did you do when you faced the problem?
We are currently using NET8
[UnsafeAccessor]
to query theDataHandle.IsAllocated
property and create a copy whenever we see this, but this isn't a valid solution. The arrayGCHandle
needs a proper lifetime management and reference counting implementation. To avoid affecting other classes descendant fromDisposableObject
, we could remove theGCHandle
management by the base class and manage it in theMat
class itself. Since this only affects submatrices, a sample solution could be:The text was updated successfully, but these errors were encountered: