Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[API Proposal]: Provide API for freeing Variant memory #79402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lowleveldesign opened this issue Dec 8, 2022 · 3 comments
Closed

[API Proposal]: Provide API for freeing Variant memory #79402

lowleveldesign opened this issue Dec 8, 2022 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices
Milestone

Comments

@lowleveldesign
Copy link

Background and motivation

It is currently quite hard to reclaim memory allocated internally by the Marshal.GetNativeVariantForObject method. Let's take the following code as an example:

var variantPtr = Marshal.AllocHGlobal(VariantTypeSize); // VariantTypeSize = 24 (x64) or 16 (x86)

Marshal.GetNativeVariantForObject("test string", variantPtr);

// pass the variantPtr to native code and do the work

Marshal.FreeHGlobal(variantPtr);

We are leaking memory because GetNativeVariantForObject assigns the string to the AsBstr property of the internal Variant type. The AsBstr property internally allocates memory using Marshal.StringToBSTR. One solution could be to provide the Marshal.FreeNativeVariant method, which would reclaim the internal memory.

API Proposal

namespace System.Runtime.InteropServices;

public static class Marshal
{
    public static void FreeNativeVariant(nint addr);
}

API Usage

var variantPtr = Marshal.AllocHGlobal(VariantTypeSize); // VariantTypeSize = 24 (x64) or 16 (x86)

Marshal.GetNativeVariantForObject("test string", variantPtr);

// pass the variantPtr to native code and do the work

Marshal.FreeNativeVariant(variantPtr);
Marshal.FreeHGlobal(variantPtr);

Alternative Designs

Another approach that comes to my mind is to modify the BStrWrapper class so it will be responsible for allocating and freeing memory for the wrapped BSTR string. Then we would need to instruct the users to use the wrapper when calling GetNativeVariantForObject as using raw string leads to a leak. GetNativeVariantForObject already accepts BStrWrapper, so we won't need to modify the public API.

Risks

No response

@lowleveldesign lowleveldesign added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Dec 8, 2022
@ghost ghost added area-Interop-coreclr untriaged New issue has not been triaged by the area owner labels Dec 8, 2022
@ghost
Copy link

ghost commented Dec 9, 2022

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

It is currently quite hard to reclaim memory allocated internally by the Marshal.GetNativeVariantForObject method. Let's take the following code as an example:

var variantPtr = Marshal.AllocHGlobal(VariantTypeSize); // VariantTypeSize = 24 (x64) or 16 (x86)

Marshal.GetNativeVariantForObject("test string", variantPtr);

// pass the variantPtr to native code and do the work

Marshal.FreeHGlobal(variantPtr);

We are leaking memory because GetNativeVariantForObject assigns the string to the AsBstr property of the internal Variant type. The AsBstr property internally allocates memory using Marshal.StringToBSTR. One solution could be to provide the Marshal.FreeNativeVariant method, which would reclaim the internal memory.

API Proposal

namespace System.Runtime.InteropServices;

public static class Marshal
{
    public static void FreeNativeVariant(nint addr);
}

API Usage

var variantPtr = Marshal.AllocHGlobal(VariantTypeSize); // VariantTypeSize = 24 (x64) or 16 (x86)

Marshal.GetNativeVariantForObject("test string", variantPtr);

// pass the variantPtr to native code and do the work

Marshal.FreeNativeVariant(variantPtr);
Marshal.FreeHGlobal(variantPtr);

Alternative Designs

Another approach that comes to my mind is to modify the BStrWrapper class so it will be responsible for allocating and freeing memory for the wrapped BSTR string. Then we would need to instruct the users to use the wrapper when calling GetNativeVariantForObject as using raw string leads to a leak. GetNativeVariantForObject already accepts BStrWrapper, so we won't need to modify the public API.

Risks

No response

Author: lowleveldesign
Assignees: -
Labels:

api-suggestion, area-System.Runtime.InteropServices, untriaged

Milestone: -

@AaronRobinsonMSFT
Copy link
Member

This is handled in Win32 via VariantClear(). When marshaling through the IL Stubs this is handled by the VM itself. It does seem like a missing low-level API. I'm not sure it is worth adding given how long it has been missing, but we can see how the community responds.

@AaronRobinsonMSFT AaronRobinsonMSFT removed the untriaged New issue has not been triaged by the area owner label Dec 9, 2022
@AaronRobinsonMSFT AaronRobinsonMSFT added this to the Future milestone Dec 9, 2022
@huoyaoyuan
Copy link
Member

System.Runtime.InteropServices.Marshalling.ComVariant is the "better" type to work with VARIANT interop now. Its Dispose method will correctly dispose referenced memory. The new work flow should be:

using var variant = ComVariant.Create("test string"); // The variant struct is allocated on stack, no need for manual AllocHGlobal/FreeHGlobal
{
    DoPInvoke(&variant); // Take the address of variant struct directly
}
// The using scope disposes referenced memory

To work with a pointer from old flow, you can cast a pointer from it:

((ComVariant*)variantPtr)->Dispose();

@jkotas jkotas closed this as completed Apr 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices
Projects
Status: No status
Development

No branches or pull requests

4 participants