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?
User contributions licensed under CC BY-SA 3.0