Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python ctypes.string_at freeing behavior

I am working with ctypes to expose some C functions from a DLL to a Python script. One of the functions returns a dynamically sized character array, and I would like to be able to read the contents of this array in Python, but also property handle freeing the memory of the array when I am done with it.

Example C code:

...

#ifdef __cplusplus
extern "C"
{
#endif
    __declspec(dllexport) char * WINAPI get_str()
    {
        int str_len = ... // figure out how long it is gonna be and set it here
        char *ary = (char *)malloc(sizeof(char) * str_len);

        // populate the array
        ...

        ary[str_len - 1] = '\0';

        return ary;
    }

#ifdef __cplusplus
}
#endif

I build my DLL, copy it over to a location it will be found, and then have this Python code:

import ctypes

my_dll = ctypes.WinDLL("MyDLLName.dll")

some_str = ctypes.string_at(my_dll.get_str())

print some_str

This code all works correctly as you would expect. My question is: because ctypes.string_at creates a string at the specified memory location, when some_str goes out of scope in the Python interpreter, will that memory be garbage collected, or do I need to free it manually?

like image 260
KSletmoe Avatar asked Oct 18 '25 00:10

KSletmoe


1 Answers

string_at creates a new Python string, in a new memory location, completly independent of the memory location it was called with.

Python or ctypes can't guess about what your native code returned it - as far as it is concerned, it is just a number (which happens to be a valid pointer in this case).

So, the rule of thumb is: if you write C code that allocates memory, you should also write equivalent C code to de-allocate it - and call that freeing C code from your ctypes-using Python code.

For quick scripts and examples like this, since you know it is a simple allocated string, you can free it straight from Python side by using ctypes to call the system free function.

That is, store the returned pointer in a Python var: (you may or may not cat it to a proper ctypes pointer type), and after running string_at, use:

pointer = my_dll.get_str()
some_str = ctypes.string_at(pointer)
# This is windows specific - 
# on Posix, one have to load "libc.so" and use "free" from there:
ctypes.cdll.msvcrt.free(pointer)
like image 92
jsbueno Avatar answered Oct 20 '25 15:10

jsbueno



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!