Re: alignment of data fields when compiling with mingwin

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A bit of googling turns this function up

Marshal.StringToHGlobalAnsi
Marshal.StringToHGlobalAuto
Marshal.StringToHGlobalUni

they create an unmanaged copy a managed string.

But those might not help, because the docs say that the returned
IntPtr must be freed using Marshal.FreeHGlobal. All this methods use
the GlobalAlloc function from the WinAPI to allocate memory. Maybe
GlobalAlloc is not compatible with the "libc" free function that
libvirt will use to free the memory.

A bit more googling told me how to import functions from DLLs in C#.
This one imports strdup:

[DllImport("msvcrt.dll"), CLSCompliant(false)]
public static extern IntPtr _strdup([Const] IntPtr strSource);

Maybe you can do something like this:

string result_original = ...;
IntPtr result_global = StringToHGlobalAuto(result_original);
IntPtr result_duplicated = _strdup(result_global);
FreeHGlobal(result_global);

Then pass result_duplicated to libvirt.

I'm not sure if that works at all. Maybe there is a simpler/better
solution for this.

Matthias

2010/10/17  <arnaud.champion@xxxxxxxxxx>:
> You are perfectly right, I have to find the way to avoid C# memory freeing !
> You're a master ;)
>
> Arnaud
>
> --------------------------------------------------
> From: "Matthias Bolte" <matthias.bolte@xxxxxxxxxxxxxx>
> Sent: Sunday, October 17, 2010 3:21 PM
> To: <arnaud.champion@xxxxxxxxxx>
> Cc: <libvir-list@xxxxxxxxxx>
> Subject: Re:  alignment of data fields when compiling with mingwin
>
>> 2010/10/17 Â<arnaud.champion@xxxxxxxxxx>:
>>>
>>> Hi Matthias,
>>>
>>> I'm working on the virConnectOpenAuth method C# binding. And in fact, It
>>> partially work. Let me explain you :
>>>
>>
>>
>>> Now, I have made a little code to connect to an esx hypervisor like this
>>> :
>>>
>>> ... some init stuff...
>>>
>>> Â Â Â Â Â// Define the virConnectAuth struct
>>> Â Â Â Â ÂvirConnectAuth auth = new virConnectAuth
>>> Â Â Â Â Â{
>>> Â Â Â Â Â Â Âcbdata = authDataPtr,
>>> Â Â Â Â Â Â Âcb = AuthCallback,
>>> Â Â Â Â Â Â Âcredtypes = credtypesPtr,
>>> Â Â Â Â Â Â Âncredtype = (uint)credtypes.Length
>>> Â Â Â Â Â};
>>>
>>> Â Â Â Â ÂIntPtr conn = libVirt.virConnectOpenAuth(tbURI.Text, ref auth,
>>> 0);
>>>
>>> I have the call back method "AuthCallback" defined like this :
>>>
>>> Â Â Âprivate int AuthCallback(IntPtr creds, uint ncred, IntPtr cbdata)
>>> Â Â Â{
>>>
>>> Â Â Â Â ÂAuthData authData = (AuthData) Marshal.PtrToStructure(cbdata,
>>> typeof (AuthData));
>>> Â Â Â Â Âint offset = 0;
>>> Â Â Â Â Âint credIndex = 0;
>>>
>>> Â Â Â Â Âwhile (credIndex < ncred)
>>> Â Â Â Â Â{
>>> Â Â Â Â Â Â ÂIntPtr currentCred = new IntPtr(creds.ToInt32() + offset);
>>>
>>> Â Â Â Â Â Â ÂvirConnectCredential cred = (virConnectCredential)
>>> Marshal.PtrToStructure(currentCred, typeof (virConnectCredential));
>>> Â Â Â Â Â Â Âoffset += Marshal.SizeOf(cred);
>>> Â Â Â Â Â Â Âswitch(cred.type)
>>> Â Â Â Â Â Â Â{
>>> Â Â Â Â Â Â Â Â Âcase virConnectCredentialType.VIR_CRED_AUTHNAME:
>>> Â Â Â Â Â Â Â Â Â Â Âcred.result = authData.user_name;
>>> Â Â Â Â Â Â Â Â Â Â Âcred.resultlen = (uint)authData.user_name.Length;
>>> Â Â Â Â Â Â Â Â Â Â Âbreak;
>>> Â Â Â Â Â Â Â Â Âcase virConnectCredentialType.VIR_CRED_PASSPHRASE:
>>> Â Â Â Â Â Â Â Â Â Â Âcred.result = authData.password;
>>> Â Â Â Â Â Â Â Â Â Â Âcred.resultlen = (uint) authData.password.Length;
>>> Â Â Â Â Â Â Â Â Â Â Âbreak;
>>> Â Â Â Â Â Â Â Â Âdefault:
>>> Â Â Â Â Â Â Â Â Â Â Âreturn -1;
>>> Â Â Â Â Â Â Â}
>>> Â Â Â Â Â Â ÂMarshal.StructureToPtr(cred, currentCred, true);
>>>
>>> Â Â Â Â Â Â ÂcredIndex++;
>>> Â Â Â Â Â}
>>> Â Â Â Â Âreturn 0;
>>> Â Â Â}
>>>
>>> When I test this code, all seems to work well, I mean the "AuthCallback"
>>> method is called twice, once for authname and once for passphrase.
>>>
>>> But when I run my code in a debugger of Visual Studio I have these
>>> messages
>>> :
>>>
>>> HEAP[Win32_virConnectOpenAuth.exe]: Invalid address specified to
>>> RtlFreeHeap( 00700000, 00EE6D78 )
>>> HEAP[Win32_virConnectOpenAuth.exe]: Invalid address specified to
>>> RtlFreeHeap( 00700000, 00EE6A80 )
>>> HEAP[Win32_virConnectOpenAuth.exe]: Invalid address specified to
>>> RtlFreeHeap( 00700000, 00EE6D78 )
>>> HEAP[Win32_virConnectOpenAuth.exe]: Invalid address specified to
>>> RtlFreeHeap( 00700000, 00EE6A80 )
>>> HEAP[Win32_virConnectOpenAuth.exe]: Invalid address specified to
>>> RtlFreeHeap( 00EE0000, 007DE480 )
>>>
>>> but the connection is done, and I am able to list domains of the
>>> hypervisor
>>> for example. The real problem is that this program only work inside the
>>> the
>>> visual studio debugger, when I launch the executable without debugger, it
>>> fails.
>>> So I am searching why this doesn't work, I want to check the bindings.
>>> And I
>>> also want to try to fill the "result" member of the virConnectCredential
>>> structure directly to understanding what can be the problem.
>>
>>
>> Okay, you see an invalid free call either because free is called on an
>> initial invalid pointer of because free is called twice on the same
>> pointer (on the second call the pointer is invalid).
>>
>> When you look at the libvirt codebase in src/util/authhelper.c in
>> virRequestUsername you'll see that the cred.result is returned to the
>> driver directly without making a copy of it. The driver is then
>> responsible for freeing this memory. So the ownership of the memory
>> cred.result points to is transferred from your callback to the driver.
>>
>> I think you see a double-free here because libvirt and C# are both
>> trying to free the same memory, but C# should not do this. I'm not
>> familiar with C#, so I'm just guessing here based on what you have
>> described. This cannot be a problem with the alignment or struct
>> layout, otherwise authentication would not work.
>>
>> You can test if it's double-free by applying the attached patch to
>> libvirt. This patch stops the virRequestUsername and
>> virRequestPassword functions from transferring ownership of the
>> cred.result by copying the string. This creates a memory leak in the
>> normal case, but should stop the double-free in case C# is freeing
>> cred.result here.
>>
>> Matthias
>>
>>
>>> Anyway, thanks ofr these informations, this can help.
>>>
>>> Best regards,
>>>
>>> Arnaud
>>>
>>> --------------------------------------------------
>>> From: "Matthias Bolte" <matthias.bolte@xxxxxxxxxxxxxx>
>>> Sent: Sunday, October 17, 2010 12:04 PM
>>> To: <arnaud.champion@xxxxxxxxxx>
>>> Cc: <libvir-list@xxxxxxxxxx>
>>> Subject: Re:  alignment of data fields when compiling with
>>> mingwin
>>>
>>>> 2010/10/15 Â<arnaud.champion@xxxxxxxxxx>:
>>>>>
>>>>> Hi,
>>>>>
>>>>> I'm currently working on libvirt csharp bindings, and I have some
>>>>> trouble
>>>>> with virConnectOpenAuth marshaling.
>>>>> I need to know what is the alignment of data fields in structure when
>>>>> compiling with mingwin.
>>>>> Anyone know that ?
>>>>>
>>>>> cheers,
>>>>>
>>>>> Arnaud Champion
>>>>>
>>>>
>>>> Why do you need to know the alignment? Do you need to build or access
>>>> members of the virConnectCredential or virConnectAuth structs by
>>>> offset in memory?
>>>>
>>>> The Wikipedia article about data structure alignment might be helpful
>>>> when you really need to care about alignment.
>>>>
>>>> If you actually need the offset of the members in those structs you
>>>> can just use the offsetof macro and let the compiler tell you:
>>>>
>>>> #include <stdio.h>
>>>> #include <stddef.h>
>>>> #include <libvirt/libvirt.h>
>>>>
>>>> void main(void)
>>>> {
>>>> Âprintf("virConnectCredential\n");
>>>> Âprintf(" Âtype   Â%2u\n", offsetof(virConnectCredential, type));
>>>> Âprintf(" Âprompt  Â%2u\n", offsetof(virConnectCredential, prompt));
>>>> Âprintf(" Âchallenge %2u\n", offsetof(virConnectCredential, challenge));
>>>> Âprintf(" Âdefresult %2u\n", offsetof(virConnectCredential, defresult));
>>>> Âprintf(" Âresult  Â%2u\n", offsetof(virConnectCredential, result));
>>>> Âprintf(" Âresultlen %2u\n", offsetof(virConnectCredential, resultlen));
>>>> Âprintf("\n");
>>>> Âprintf("virConnectAuth\n");
>>>> Âprintf(" Âcredtype Â%2u\n", offsetof(virConnectAuth, credtype));
>>>> Âprintf(" Âncredtype %2u\n", offsetof(virConnectAuth, ncredtype));
>>>> Âprintf(" Âcb    Â%2u\n", offsetof(virConnectAuth, cb));
>>>> Âprintf(" Âcbdata  Â%2u\n", offsetof(virConnectAuth, cbdata));
>>>> }
>>>>
>>>>
>>>> Output on x86:
>>>>
>>>> virConnectCredential
>>>> Âtype    0
>>>> Âprompt   4
>>>> Âchallenge Â8
>>>> Âdefresult 12
>>>> Âresult  Â16
>>>> Âresultlen 20
>>>>
>>>> virConnectAuth
>>>> Âcredtype  0
>>>> Âncredtype Â4
>>>> Âcb     8
>>>> Âcbdata  Â12
>>>>
>>>>
>>>> Output on x86_64:
>>>>
>>>> virConnectCredential
>>>> Âtype    0
>>>> Âprompt   8
>>>> Âchallenge 16
>>>> Âdefresult 24
>>>> Âresult  Â32
>>>> Âresultlen 40
>>>>
>>>> virConnectAuth
>>>> Âcredtype  0
>>>> Âncredtype Â8
>>>> Âcb    Â16
>>>> Âcbdata  Â24
>>>>
>>>> [1]
>>>>
>>>> http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86
>>>>
>>>> Matthias
>>>
>>>
>>>
>>
>
>

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]