How to allocate and de-allocate memory for CFFI structure

83 views
Skip to first unread message

ashwin kumar

unread,
Apr 25, 2016, 1:38:38 AM4/25/16
to python-cffi

I have structure in C++ as below

typedef struct user
{
    unsigned long           id;
    char                   *name;
    struct1                 type;
    int                     Period;
    char                   *altername;
    char                   *description;
    struct2                 state;
    struct3                *userDetails;
} CUser;

typedef struct _CDeltaUser
{
    CUser                  *deltaUser;
    struct3                *deletedUserDetails;
    struct3                *changedUserValues;
} CDeltaUser;

I am trying to create a object for this structure through CFFI and assign the values for the members and pass the created object to a API in C++.

deltaUser = ffi.new("CDeltaUser*")

deltaUser.deltaUser = ffi.new("CUser*") 

deltaUser.deltaUser.id=4

Now when i try to pass this deltaUser to an API in C++ through the dll loaded using ffi.dlopenApiName(par1,par2,deltaUser,par4) python crashes at this point. crash occurs both in windows and Linux.

What is wrong with this code ? I am using windows 7 64 bit , python2.7 and cffi 1.5.2

On debugging I could able to find that that the values passed gets optimized before hitting the API.

On checking the python CFFI source codes I can able to find that padding/8 bit alignment is done in some part of codes.

Is this a bug in CFFI or how can i overcome this problem form my script/c++ code side?

Thanks in advance. 



ffi64.c

Mark Harviston

unread,
Apr 25, 2016, 2:16:32 PM4/25/16
to python-cffi
I haven't looked at the code you attached, so I could be mistaken, but it looks like here:


deltaUser.deltaUser = ffi.new("CUser*")

Here you're creating a reference and storing it in a variable, but there are no references in a python variable so it get's garbage collected.


ashwin kumar

unread,
Apr 26, 2016, 12:47:04 AM4/26/16
to python-cffi
Hi Mark,

Thanks for your time. 
but the problem i feel is the padding of the structure members. When there is no padding occurs it works fine. say in case every structure variable is 8 bytes then it works fine.
Feels like some memory alignment is done on cffi/python source codes.

Thanks

Armin Rigo

unread,
Apr 26, 2016, 4:49:06 AM4/26/16
to pytho...@googlegroups.com
Hi,

On 26 April 2016 at 06:47, ashwin kumar <ashwink...@gmail.com> wrote:
> Thanks for your time.
> but the problem i feel is the padding of the structure members.

Mark's comment is correct, though. Your code is definitely broken at
the line he pointed out. (There might be other issues with alignment,
of course.)


A bientôt,

Armin.

Damien Ruiz

unread,
Apr 28, 2016, 4:17:44 PM4/28/16
to python-cffi, ar...@tunes.org
I had a similar issue that was solved by doing something similar to:

First, make a C function to allocate your structure and set their values to NULL.

CUser* CreatePointerCUser(){
   
CUser* pCUser = ( CUser* ) malloc( sizeof( CUser ) );
    _SetDummyValues
( pCUser );    // That function sets attribute to 0 and NULL depending on their type.
   
return pCUser;
}

I suggest you to do that kind of function for all the C structure you will allocate.

Then, make its related function to destroy your C data structure properly. Pretty much like a C++ pair of constructor / destructor.

It would be something like:

void FreeCUser( CUser* pCUser )
{
    pCUser
->id = 0;      // That line...
    free
( pCUser->name );
    pCUser
->name = NULL; // And that line may look like overkilling it but at least your memory will be set to 0 values
}


Finally, in Python, instantiate your values using:

gc_pCUser = ffi.gc( c.CreateCUser(), c.FreeCUser )


That's what saved me!
I hope that helped.

Related links: my stackoverflow thread when I had the same kind of issue, another stackoverflow thread


Damien

Damien Ruiz

unread,
Apr 28, 2016, 4:19:26 PM4/28/16
to python-cffi, ar...@tunes.org
I made a mistake :


Finally, in Python, instantiate your values using:
gc_pCUser = ffi.gc( c.CreatePointerCUser(), c.FreeCUser )



Damien

Armin Rigo

unread,
Apr 29, 2016, 2:30:44 AM4/29/16
to Damien Ruiz, python-cffi
Hi Damien,

On 28 April 2016 at 22:17, Damien Ruiz <ruiz...@gmail.com> wrote:
> That's what saved me!

Well, as posted, your code leaks because it never calls `free(pCUser)`.


A bientôt,

Armin.

Damien Ruiz

unread,
Apr 29, 2016, 11:33:33 AM4/29/16
to python-cffi, ruiz...@gmail.com, ar...@tunes.org
Hi Armin,

You are right, the program was leaking. Well seen, thank you!

Hence, the free functions now look like:

void FreeCUser( CUser* pCUser )
{

    if( pCUser != NULL )
    {
        if( pCUser->name != NULL )
        {   
            free
( pCUser->name );
            pCUser
->name = NULL;
        }
        pCUser->id = 0;
   
        ... // other free and reset for the members

        free( pCUser );
        pCUser = NULL;
    }
}

By the way, doing that "if( pCUser != NULL )" gives me a considerable speed improvement. Checking if a pointer is free must be faster than just passing it to the free function and let it figure it out.


Damien
Reply all
Reply to author
Forward
0 new messages