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

Re: [libvirt] alignment of data fields when compiling with mingwin



2010/10/17  <arnaud champion devatom fr>:
> 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 googlemail com>
> Sent: Sunday, October 17, 2010 12:04 PM
> To: <arnaud champion devatom fr>
> Cc: <libvir-list redhat com>
> Subject: Re: [libvirt] alignment of data fields when compiling with mingwin
>
>> 2010/10/15  <arnaud champion devatom fr>:
>>>
>>> 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
>
>
>
diff --git a/src/util/authhelper.c b/src/util/authhelper.c
index 9398cb3..c4ad9ce 100644
--- a/src/util/authhelper.c
+++ b/src/util/authhelper.c
@@ -61,7 +61,7 @@ virRequestUsername(virConnectAuthPtr auth, const char *defaultUsername,
         cred.resultlen = 0;
 
         if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
-            VIR_FREE(cred.result);
+            /*VIR_FREE(cred.result);*/
         }
 
         break;
@@ -69,7 +69,7 @@ virRequestUsername(virConnectAuthPtr auth, const char *defaultUsername,
 
     VIR_FREE(prompt);
 
-    return cred.result;
+    return strdup(cred.result);
 }
 
 
@@ -103,7 +103,7 @@ virRequestPassword(virConnectAuthPtr auth, const char *username,
         cred.resultlen = 0;
 
         if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
-            VIR_FREE(cred.result);
+            /*VIR_FREE(cred.result);*/
         }
 
         break;
@@ -111,5 +111,5 @@ virRequestPassword(virConnectAuthPtr auth, const char *username,
 
     VIR_FREE(prompt);
 
-    return cred.result;
+    return strdup(cred.result);
 }

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