2010/10/19 Eric Blake <eblake(a)redhat.com>:
On 10/19/2010 07:13 AM, arnaud.champion(a)devatom.fr wrote:
>
> ?Well, as I have said I work on .Net/Mono bindings.
>
> To make bindings, we use largely the marshaling methods of .Net/Mono. I
> was working on bindings virConnectOpenAuth, so I have de marshal
> virConnectCredential struct, these kind of thing. Matthias Bolte help me
> a lot to make all the process thru callback working. And we have
> discover that the virConnectCredential was reseted by the marshaling
> process (in particular marshaling process free the result member of the
> virConnectCredential, and in fact, for libvirt, it's the driver
> responsability to free the result member). So Matthias suggest me to
> bind strdup to .Net and use it to be sure that the result member is not
> freed by marshaling. And it works.
strdup() is nothing more than malloc() followed by strcpy(); it is such a
fundamental operation to copy strings into newly allocated memory that I'm
surprised that you don't know how to do that natively in C# without having
to bind in strdup() in the first place (even if you do have to do it in two
phases of allocation and copying rather than as a single function call).
The problem is to get the result into unmanaged memory on the correct heap.
The ownership of cred.result is transferred to the driver that calls
free() on it when done. Therefore, you cannot pass a pointer to the
data of a managed string from C# to the libvirt driver, because that
creates a double/invalid-free.
C# provides Marshal.StringToHGlobalAuto() that created a copy of a
string in memory allocated using GlobalAlloc() from the WinAPI. The
docs emphasis that this copy must be freed using GlobalFree() that
might be incompatible with free(), I'm not sure. Because of that I
suggested to do a strdup() of the result from
Marshal.StringToHGlobalAuto() to make sure cred.result can be freed
using free().
See [1] for more details. When I understood Arnaud correctly then
passing the result of Marshal.StringToHGlobalAuto() directly as
cred.result didn't work, but passing the result from strdup() works.
The sole purpose of all this is just to get cred.result allocated in
unmanaged memory that can be freed using free().
Marshal.StringToHGlobalAuto() + strdup() just works for now but is
ugly. Arnaud said that he is working on a better approach for this
(custom marshaling), that doesn't require strdup().
[1]
https://www.redhat.com/archives/libvir-list/2010-October/msg00525.html
Matthias