Skip to content
Memory and resource safety Reviewed 2026-09-13

Safe Handle

What does this mean ?

DangerousGetHandle() exposes a native handle without acquiring a lifetime reference. Another thread may dispose the wrapper while unmanaged code uses the raw value. A recycled handle can then identify a different resource. Microsoft documents these lifetime hazards.

What can happen ?

Premature release can cause failures or access to an unintended resource. Consequences depend on the native API and resource; merely calling this method is not proof of a data breach. Ownership mistakes relate to improper resource lifetime control, CWE-664.

Recommendation

Prefer a managed API or a P/Invoke signature accepting the appropriate SafeHandle type. When legacy interop requires raw access, acquire and release a lifetime reference reliably. This does not validate native arguments or make an arbitrary pointer safe.

Sample Code

These fragments assume a valid, owned SafeHandle handle. NativeRead is a synchronous native call that neither closes nor retains the borrowed handle. No caller may independently close or invalidate it outside the wrapper's ownership contract.

Unprotected lifetime:

NativeRead(handle.DangerousGetHandle());

Bounded legacy interop:

bool added = false;
try
{
    handle.DangerousAddRef(ref added);
    if (handle.IsInvalid)
        throw new InvalidOperationException("Invalid native handle");
    NativeRead(handle.DangerousGetHandle());
}
finally
{
    if (added) handle.DangerousRelease();
}

Regression test: with a test handle, call Dispose() during NativeRead and assert that final release occurs only after the borrowed operation finishes. Make NativeRead throw and verify release still occurs. A disposed wrapper must fail before native work begins.

References