Possible memory leak with ctypes

1

I´m using some library using ctypes. This library has its own methods to handle heap memory, so in C i would do something like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intcall.h"

int main(void) {
    long status = -1;
    char host[10] = "xx.x.x.xx";
    char user[7] = "xxxxxx";
    char pass[7] = "xxxxxx";
    char acc[10] = "xxxxxxxxx";
    long sess = ic_universe_session(host, user, pass, acc, &status, NULL);
    if (status == 0)
    {
        char sub_name[14] = "PRUEBA_XXXXXX";
        long sub_name_len = 13;
        unsigned char param1_txt[5] = "AAAA";
        long size1 = 5;
        long num_params = 2;
        //void * FAR PASCAL ic_malloc ic_proto((LPLONG));
        char* param1 = ic_malloc(&size1);
        memcpy(param1, param1_txt, size1);
        /*  typedef struct icstring {
                long len;
                unsigned char * text;
            } ICSTRING; */
        ICSTRING icstr1;
        icstr1.len = size1; icstr1.text = param1;
        ICSTRING icstr2;
        icstr2.len = 0;
        ic_subcall(sub_name, &sub_name_len, &status, &num_params, &icstr1, &icstr2);
        //void FAR PASCAL ic_free ic_proto((void *));
        ic_free(icstr1.text);
        ic_free(icstr2.text);
    }
    return EXIT_SUCCESS;
}

The library can free and remalloc the pointer I passed to it so this is why I need to free icstr1.text and not param1, the return pointer from ic_malloc.

In python a similar example would be like this:

subrutina = 'PRUEBA_XXXXXX'
argumento = 'AAAA'
num_params = 2
argumentos_tipo = [c_char_p, POINTER(c_long), POINTER(c_long), POINTER(c_long)]
self.__U2_C_INTERFACE.ic_calloc.argtypes = [POINTER(c_long)]
self.__U2_C_INTERFACE.ic_free.argtypes = [ctypes.c_voidp]
self.__U2_C_INTERFACE.ic_subcall.argtypes = argumentos_tipo
sub_name_in = c_char_p(bytes(subrutina, self.__sistema_codificacion))
sub_name_len_in = c_long(len(subrutina))
num_params_len_in = c_long(num_params)
code = c_long(0)
p_in = [None] * num_params
mem_alloc = [c_char_p(0)] * num_params
byte_param = bytes(argumento, self.__sistema_codificacion)
byte_size = len(byte_param)
p_in[0] = ICString(c_long(0))
p_in[0].len = c_long(byte_size)
mem_alloc[0] = c_char_p(self.__U2_C_INTERFACE.ic_calloc(byref(c_long(byte_size + 1))))
tam = byte_size * sizeof(ctypes.c_char)
ctypes.memmove(mem_alloc[0], byte_param, tam)
p_in[0].text = mem_alloc[0]
p_in[1] = ICString(c_long(0))
self.__U2_C_INTERFACE.ic_subcall(sub_name_in,
                                 byref(sub_name_len_in),
                                 byref(code),
                                 byref(num_params_len_in),
                                 *[byref(n) for n in p_in])
if int(code.value) != 0:
    err_msg = 'Error subrutina %s: %s' % (subrutina, UniverseConstants.error_message(code.value))
    from pyuniverse.pyuniverse.UniverseExceptions import UniverseCommandException
    raise UniverseCommandException(err_msg)
# copiar los resultados
for idx, parametro in enumerate(p_in):
    print(p_in[idx].text)
    # if p_in[idx].len > 0:
    #     temp = ctypes.cast(p_in[idx].text, ctypes.c_void_p)
    #     self.__U2_C_INTERFACE.ic_free(temp)

But the call to ic_free is causing trouble in the heap: Process finished with exit code -1073740940 (0xC0000374). This means "Heap Corruption Exception 0xC0000374"

I tried to track the memory usage using more input parameters using pympler. With two parameters, I get this:

                                 types |   # objects |   total size
================================================ | =========== | ============
                                    <class 'dict |           4 |    640     B
                  <class '_ctypes.PyCPointerType |           1 |    492     B
  <class 'ctypes.CDLL.__init__.<locals>._FuncPtr |           4 |    480     B
              <class 'builtin_function_or_method |           7 |    252     B
                                    <class 'list |           5 |    236     B
                                   <class 'tuple |           5 |    184     B
                                 <class 'StgDict |           1 |    148     B
                                    <class 'type |           0 |    144     B
                                     <class 'str |           3 |    127     B
                       <class 'getset_descriptor |           2 |     80     B
                                 <class 'weakref |           1 |     44     B
                                     <class 'int |           1 |     16     B

and with ten parameters:

                                           types |   # objects |   total size
================================================ | =========== | ============
                                    <class 'dict |           4 |    640     B
                  <class '_ctypes.PyCPointerType |           1 |    492     B
  <class 'ctypes.CDLL.__init__.<locals>._FuncPtr |           4 |    480     B
              <class 'builtin_function_or_method |           7 |    252     B
                                    <class 'list |           5 |    268     B
                                   <class 'tuple |           5 |    184     B
                                 <class 'StgDict |           1 |    148     B
                                    <class 'type |           0 |    144     B
                                     <class 'str |          11 |    401     B
                       <class 'getset_descriptor |           2 |     80     B
                                 <class 'weakref |           1 |     44     B
                                     <class 'int |           1 |     16     B

The main difference is in the class "str":

Two params: <class 'str |           3 |    127     B
Ten params: <class 'str |          11 |    401     B

Is this memory going to be handled by python´s garbage collector? Am I missing something? Is some memory leak I´m not seeing with pympler?

python
python-3.x
memory-leaks
ctypes
asked on Stack Overflow Aug 17, 2018 by Héctor C.

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0