Skip to content

SafeHandle marshalling improvements in the source-generated marshalling #73496

Closed
@jkoritzinsky

Description

@jkoritzinsky

From #69608:

  1. SafeHandle disposal. When marshaling out a SafeHandle, the generator emits code like this:
            __retVal = new global::Microsoft.Win32.SafeHandles.SafeFindHandle();
            try
            {
                //
                // Pin
                //
                fixed (void* __lpFileName_gen_native__pinned = lpFileName)
                {
                    ushort* __lpFileName_gen_native = (ushort*)__lpFileName_gen_native__pinned;
                    fixed (global::Interop.Kernel32.WIN32_FIND_DATA* __lpFindFileData_gen_native = &lpFindFileData)
                    {
                        {
                            System.Runtime.InteropServices.Marshal.SetLastSystemError(0);
                            __retVal_gen_native = __PInvoke__(__lpFileName_gen_native, fInfoLevelId, __lpFindFileData_gen_native, fSearchOp, lpSearchFilter, dwAdditionalFlags);
                            __lastError = System.Runtime.InteropServices.Marshal.GetLastSystemError();
                        }
                    }
                }

                __invokeSucceeded = true;
            }
            finally
            {
                if (__invokeSucceeded)
                {
                    //
                    // GuaranteedUnmarshal
                    //
                    System.Runtime.InteropServices.Marshal.InitHandle(__retVal, __retVal_gen_native);
                }
            }

It's using a try/finally and __invokeSucceeded, so it's trying to accomodate something in that try region throwing. But if something there does throw, the allocated SafeHandle won't be disposed, which will in turn leave it for finalization. Should there be a catch block?

catch
{
    __retVal.Dispose();
    throw;
}

or potentially instead a catch with an exception filter that does the disposal and returns false to avoid interrupting the unwind?

In .NET 8, we'll look at moving the SafeHandle marshalling into a custom marshaller type. When we do so, we'll address this feedback.

Note for future self: This would be a good use case for the OnInvoked custom marshaller method that isn't a GC.KeepAlive usage.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions