Repository: dotnet/runtime
File: src/coreclr/vm/dispparammarshaler.cpp (C++)

Code before:
    {
        THROWS;
        GC_TRIGGERS;
        MODE_COOPERATIVE;
        PRECONDITION(CheckPointer(pRefVar));
    }
    CONTRACTL_END;

    VARTYPE RefVt = V_VT(pRefVar) & ~VT_BYREF;
    VARIANT vtmp;

    // Clear the contents of the original variant.
    OleVariant::ExtractContentsFromByrefVariant(pRefVar, &vtmp);
    SafeVariantClear(&vtmp);

    UnmanagedCallersOnlyCaller target(METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_UCO);

    struct
    {
        OBJECTREF CustomMarshaler;
    } gc;
    gc.CustomMarshaler = m_pCMInfo->GetCustomMarshaler();
    GCPROTECT_BEGIN(gc);

    // Convert the object using the custom marshaler.
    IUnknown* pUnkResult = V_UNKNOWN(&vtmp);

    target.InvokeThrowing(
        &gc.CustomMarshaler,
        pSrcObj,
        &pUnkResult);

    V_UNKNOWN(&vtmp) = pUnkResult;
    GCPROTECT_END();
    V_VT(&vtmp) = m_vt;

    // Call VariantChangeType if required.
    if (V_VT(&vtmp) != RefVt)
    {
        HRESULT hr = SafeVariantChangeType(&vtmp, &vtmp, 0, RefVt);
        if (FAILED(hr))
        {
            SafeVariantClear(&vtmp);
            if (hr == DISP_E_TYPEMISMATCH)
                COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT);
            else
                COMPlusThrowHR(hr);
        }
    }

    // Copy the converted variant back into the byref variant.

Review comment (suggestion):
The initialization of `pUnkResult` reads from `V_UNKNOWN(&vtmp)` after `SafeVariantClear(&vtmp)` has been called on line 655. Since `SafeVariantClear` sets the variant contents to zero/null, this will always initialize `pUnkResult` to NULL. While this is functionally correct (the managed method writes a new value to the pointer location), it would be clearer to explicitly initialize it as `IUnknown* pUnkResult = NULL;` to match the pattern used in `MarshalManagedToNative` at line 596 and avoid the unnecessary read from the cleared VARIANT.
```suggestion
    IUnknown* pUnkResult = NULL;
```

Code after:
    {
        THROWS;
        GC_TRIGGERS;
        MODE_COOPERATIVE;
        PRECONDITION(CheckPointer(pRefVar));
    }
    CONTRACTL_END;

    VARTYPE RefVt = V_VT(pRefVar) & ~VT_BYREF;
    VARIANT vtmp;

    // Clear the contents of the original variant.
    OleVariant::ExtractContentsFromByrefVariant(pRefVar, &vtmp);
    SafeVariantClear(&vtmp);

    UnmanagedCallersOnlyCaller target(METHOD__MNGD_REF_CUSTOM_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_UCO);

    struct
    {
        OBJECTREF CustomMarshaler;
    } gc;
    gc.CustomMarshaler = m_pCMInfo->GetCustomMarshaler();
    GCPROTECT_BEGIN(gc);

    // Convert the object using the custom marshaler.
    IUnknown* pUnkResult = NULL;

    target.InvokeThrowing(
        &gc.CustomMarshaler,
        pSrcObj,
        &pUnkResult);

    V_UNKNOWN(&vtmp) = pUnkResult;
    GCPROTECT_END();
    V_VT(&vtmp) = m_vt;

    // Call VariantChangeType if required.
    if (V_VT(&vtmp) != RefVt)
    {
        HRESULT hr = SafeVariantChangeType(&vtmp, &vtmp, 0, RefVt);
        if (FAILED(hr))
        {
            SafeVariantClear(&vtmp);
            if (hr == DISP_E_TYPEMISMATCH)
                COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT);
            else
                COMPlusThrowHR(hr);
        }
    }

    // Copy the converted variant back into the byref variant.