0

I'm trying to program with the python code which include one lib.so file. The C language had a callback method, wants me to put my string into given address.

I have spent a whole week to solve this problem.... Now, I've passed the string to C. But the next problem arises... "C" can't free() my string pointer which create by python.

Error in `/usr/bin/python': free(): invalid pointer

I've omitted the other head code

typedef struct
{
    int (*Info) (int resId,char **outbuff);
} OptFuncs;

here's the C code


OptFuncs g_sdk_opt_funcs = {NULL};


int SDK_INIT(OptFuncs *optfuncs)
{
    g_sdk_opt_funcs = *optfuncs;
    return 0;
}

int SDK_RUN()
{
    resId = 6604;
    char *szvalbuf = NULL;

    g_sdk_opt_funcs.Info(resId,&szvalbuf);

    if(szvalbuf) {free(szvalbuf); szvalbuf = NULL;}
    // I guess that's the problem.

    return 0;
}

here is the sample using C language:

int myInfo(int resId,char **outbuff)
{
    int iret = 0;
    *outbuff = NULL;

    char buff[512];
    int  buflen = sizeof(buff);
    memset(buff,0,sizeof(buff));

    if(resId == 6604)
    {
    snprintf(buff,buflen,"4GB");
    }

    if(iret == 0)
    {
        *outbuff = (char*)malloc(strlen(buff)+1);
        strcpy(*outbuff,buff);
    }

    return iret;
}

int main(int argc, char *argv[])
{
    OptFuncs optfuncs={NULL};
    optfuncs.Info = myInfo;

    int ret = SDK_INIT(&optfuncs);
    ret = SDK_RUN();
}

It works with pure C.

and my python function was:


lib = CDLL('./lib/lib.so')

infoCallback = CFUNCTYPE(c_int, c_int, POINTER(POINTER(c_char)))

class OptFuncs(Structure):
    _fields_ = [("Info", infoCallback)]

def my_info(res_id, out_buff):
    iret = 0
    out_buff[0] = None
    if res_id == 6604:
        buff = '16GB'

    char_array = create_string_buffer(buff)
    out_buff[0] = cast(char_array, POINTER(c_char))
    return iret


optFuncs = OptFuncs()
optFuncs.Info = infoCallback(my_info)

# initialize the lib‘s callback.
lib.SDK_INIT.argtypes = [POINTER(OptFuncs)]
ret = lib.SDK_INIT(pointer(optFuncs))

# run the lib‘s main func.
ret = lib.SDK_RUN()

And then the error happens.

Error in `/usr/bin/python': free(): invalid pointer

Did I do it wrong?

2

1 Answer 1

1

The problem is that memory is allocated by create_string_buffer in Python's C runtime library, and freed in the DLL's runtime library. They may not be compiled with the same version of compiler, and we don't know internally how create_string_buffer allocates the buffer. The pointer that the DLL receives may not be the pointer allocated. create_string_buffer may allocate more than you expect to store ctypes metadata. You don't want to be freeing memory managed by Python.

To fix this, ensure the data is allocated and freed in the DLL. For example add this function to the DLL and call it instead of create_string_buffer:

C

API char* SDK_MALLOC(const char* buff)
{
    char* s = malloc(strlen(buff) + 1);
    strcpy(s,buff);
    return s;
}

Python

lib.SDK_MALLOC.argtypes = ()
lib.SDK_MALLOC.restype = POINTER(c_char)

my_info becomes:

def my_info(res_id, out_buff):
    iret = 0
    out_buff[0] = None
    if res_id == 6604:
        buff = b'16GB'
    char_array = lib.SDK_MALLOC(buff)
    out_buff.contents = char_array
    return iret
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.