Skip to content

Migrate native pointer management to SafeHandle#1824

Draft
shimat wants to merge 8 commits intosafehandle_devfrom
safehandle
Draft

Migrate native pointer management to SafeHandle#1824
shimat wants to merge 8 commits intosafehandle_devfrom
safehandle

Conversation

@shimat
Copy link
Owner

@shimat shimat commented Feb 25, 2026

Summary

Replace raw IntPtr pointer management in DisposableCvObject and all derived classes with SafeHandle-based resource tracking. The ptr field is now a read-only computed property backed by a single SafeHandle instance, eliminating an entire class of use-after-free and double-free bugs.

Motivation

The previous design stored native pointers in a mutable protected IntPtr ptr field. This made it possible to:

  • Use the pointer after disposal (no CLR-level protection)
  • Forget to release native resources (pointers not tracked by the GC's ref-counting finalizer)
  • Accidentally overwrite or leak pointers during reassignment

SafeHandle is the .NET-recommended pattern for wrapping native resources. It provides atomic release guarantees, prevents handle recycling attacks, and integrates with the CLR's P/Invoke marshalling layer.

Design

Core change in DisposableCvObject:

  • ptr is now protected IntPtr ptr => safeHandle?.DangerousGetHandle() ?? IntPtr.Zero; (read-only)
  • A private OpenCvSafeHandle? safeHandle field is the single source of truth
  • SetSafeHandle() replaces the handle and invalidates any previous one
  • DisposeManaged() disposes the SafeHandle

New types:

  • OpenCvSafeHandle — abstract base (SafeHandle where IntPtr.Zero is invalid)
  • OpenCvPtrSafeHandle — delegate-based handle that calls a supplied Action<IntPtr> on release, avoiding the need for hundreds of per-type SafeHandle subclasses
  • MatSafeHandle — dedicated SafeHandle for Mat (the most frequently used type)

Inner Ptr classes (cv::Ptr<T> wrappers):

  • Ptr base constructor now accepts Action<IntPtr>? releaseAction
  • ~111 inner Ptr classes pass their delete function as a static lambda:
    class Ptr(IntPtr ptr) : OpenCvSharp.Ptr(ptr,
        static h => NativeMethods.HandleException(NativeMethods.xxx_delete(h)))
  • Redundant DisposeUnmanaged() overrides that only called base.DisposeUnmanaged() have been removed

Non-owning handles:

  • Classes like InputArray, VectorOf*, and KalmanFilter that manage their own delete calls in DisposeUnmanaged() use ownsHandle: false SafeHandles (the handle just stores the pointer value)

Changes

  • 203 files changed, +1,126 / −1,446 lines
  • 3 new files: OpenCvSafeHandle.cs, OpenCvPtrSafeHandle.cs, MatSafeHandle.cs
  • All ptr = direct writes eliminated — no code can assign to ptr anymore
  • All out ptr patterns converted to out var p + SetSafeHandle()
  • Added .github/copilot-instructions.md (UTF-8 BOM encoding policy)

Breaking changes

None for public API consumers. The ptr property is protected, so only subclasses are affected. Any external subclass of DisposableCvObject that was writing to ptr directly will need to call SetSafeHandle() instead.

@shimat shimat self-assigned this Feb 25, 2026
@shimat shimat changed the base branch from main to safehandle_dev February 28, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant