Make the conv functions more robust.

Now we may leak the strings from _(c)fruni which should be looked up
case by case. The positive side is that we no longer point to (possibly)
invalid memory.

Strings used with touni funcs are suspected to leak as well.
This commit is contained in:
Kai Huuhko 2013-03-26 18:53:13 +00:00
parent 37b8ff89ae
commit 0f3c3999e3
3 changed files with 102 additions and 57 deletions

View File

@ -221,7 +221,8 @@
include "widget_header.pxi" include "widget_header.pxi"
from libc.stdlib cimport free from libc.stdlib cimport malloc, free
from libc.string cimport memcpy
from object cimport Object from object cimport Object
@ -756,31 +757,26 @@ cdef class Window(Object):
""" """
def __set__(self, list profiles): def __set__(self, list profiles):
cdef unsigned int count = len(profiles) self.available_profiles_set(profiles)
elm_win_available_profiles_set(self.obj, convert_python_list_strings_to_array_of_strings(profiles), count)
def __get__(self): def __get__(self):
return self.available_profiles_get()
cpdef available_profiles_set(self, list profiles):
cdef: cdef:
char **profiles const_char **array
unsigned int count unsigned int arr_len = len(profiles)
unsigned int i
ret = elm_win_available_profiles_get(self.obj, &profiles, &count) try:
if ret is 0: array = convert_python_list_strings_to_array_of_strings(profiles)
raise RuntimeError("No available profiles") elm_win_available_profiles_set(self.obj, array, arr_len)
finally:
for i in range(arr_len):
free(<void *>array[i])
free(array)
return convert_array_of_strings_to_python_list(profiles, count) cpdef available_profiles_get(self):
def available_profiles_set(self, list profiles):
cdef:
unsigned int count = len(profiles)
const_char **lst = convert_python_list_strings_to_array_of_strings(profiles)
elm_win_available_profiles_set(self.obj, lst, count)
for i in range(count):
free(<void *>lst[i])
free(lst)
def available_profiles_get(self):
cdef: cdef:
char **profiles char **profiles
unsigned int count unsigned int count

View File

@ -17,6 +17,7 @@
from cpython cimport PyObject, Py_INCREF, Py_DECREF#, PyMem_Malloc, PyMem_Free from cpython cimport PyObject, Py_INCREF, Py_DECREF#, PyMem_Malloc, PyMem_Free
from libc.stdlib cimport malloc, free from libc.stdlib cimport malloc, free
from libc.string cimport memcpy, strdup
from efl cimport Eina_Bool, const_Eina_List, eina_list_append, const_void from efl cimport Eina_Bool, const_Eina_List, eina_list_append, const_void
from efl.c_eo cimport Eo as cEo from efl.c_eo cimport Eo as cEo
from efl.c_eo cimport eo_init, eo_shutdown, eo_del, eo_unref, eo_wref_add, eo_add, Eo_Class from efl.c_eo cimport eo_init, eo_shutdown, eo_del, eo_unref, eo_wref_add, eo_add, Eo_Class
@ -37,46 +38,85 @@ cdef int PY_REFCOUNT(object o):
cdef unicode _touni(char* s): cdef unicode _touni(char* s):
"""
Converts a char * to a python string object
Note: Remember to free the char * when it's no longer needed.
"""
return s.decode('UTF-8', 'strict') if s else None return s.decode('UTF-8', 'strict') if s else None
cdef unicode _ctouni(const_char *s): cdef unicode _ctouni(const_char *s):
"""
Converts a const_char * to a python string object
Note: Remember to free the const_char * when it's no longer needed.
"""
return s.decode('UTF-8', 'strict') if s else None return s.decode('UTF-8', 'strict') if s else None
cdef char *_fruni(s): cdef char *_fruni(object s):
cdef char *c_string """
Converts a python string object to a char *
Note: Remember to free the char * when it's no longer needed.
"""
cdef:
char *c_string
str string
unicode unistr
if s is None: if s is None:
return NULL return NULL
if isinstance(s, unicode): if isinstance(s, unicode):
string = s.encode('UTF-8') unistr = s
# XXX: We lose reference here string = unistr.encode('UTF-8')
c_string = string return strdup(string)
elif isinstance(s, str): elif isinstance(s, str):
c_string = s return strdup(s)
# XXX: Reference is lost unless the user keeps the string object around
else: else:
raise TypeError("Expected str or unicode object, got %s" % (type(s).__name__)) raise TypeError("Expected str or unicode object, got %s" % (type(s).__name__))
return c_string
cdef const_char *_cfruni(s): cdef const_char *_cfruni(object s):
cdef const_char *c_string """
Converts a python string object to a const_char *
Note: Remember to free the const_char * when it's no longer needed.
"""
cdef:
const_char *c_string
str string
unicode unistr
if s is None: if s is None:
return NULL return NULL
if isinstance(s, unicode): if isinstance(s, unicode):
string = s.encode('UTF-8') unistr = s
# XXX: We lose reference here string = unistr.encode('UTF-8')
c_string = string return strdup(string)
elif isinstance(s, str): elif isinstance(s, str):
c_string = s return strdup(s)
# XXX: Reference is lost unless the user keeps the string object around
else: else:
raise TypeError("Expected str or unicode object, got %s" % (type(s).__name__)) raise TypeError("Expected str or unicode object, got %s" % (type(s).__name__))
return c_string
cdef convert_array_of_strings_to_python_list(char **array, int array_length): cdef list convert_array_of_strings_to_python_list(char **array, int array_length):
"""
Converts an array of strings to a python list.
Note: Remember to free the array when it's no longer needed.
"""
cdef char *string cdef char *string
ret = [] ret = []
@ -89,24 +129,37 @@ cdef convert_array_of_strings_to_python_list(char **array, int array_length):
cdef const_char ** convert_python_list_strings_to_array_of_strings(list strings): cdef const_char ** convert_python_list_strings_to_array_of_strings(list strings):
"""
Converts a python list to an array of strings.
Note: Remember to free the array when it's no longer needed.
"""
cdef: cdef:
const_char **lst const_char **array
unsigned int arr_len = len(strings)
const_char *string const_char *string
int count = len(strings) unsigned int str_len
unsigned int i
lst = <const_char **>malloc(count * sizeof(const_char*)) array = <const_char **>malloc(arr_len * sizeof(const_char*))
for i in range(count): if not array:
raise MemoryError()
for i in range(arr_len):
string = _cfruni(strings[i]) string = _cfruni(strings[i])
str_len = len(strings[i]) str_len = len(string)
lst[i] = <const_char *>malloc(str_len + 1) array[i] = <const_char *>malloc(str_len + 1)
memcpy(lst[i], string, str_len + 1) memcpy(array[i], string, str_len + 1)
# Note: Always make sure that the array is freed at the other end. # Note: Always make sure that the array is freed at the other end
return lst return array
cdef convert_eina_list_strings_to_python_list(const_Eina_List *lst): cdef list convert_eina_list_strings_to_python_list(const_Eina_List *lst):
cdef const_char *s cdef:
ret = [] const_char *s
list ret = []
while lst: while lst:
s = <const_char *>lst.data s = <const_char *>lst.data
if s != NULL: if s != NULL:
@ -122,7 +175,7 @@ cdef Eina_List * convert_python_list_strings_to_eina_list(strings):
return lst return lst
cdef _object_list_to_python(const_Eina_List *lst): cdef list _object_list_to_python(const_Eina_List *lst):
ret = [] ret = []
while lst: while lst:
ret.append(object_from_instance(<cEo *>lst.data)) ret.append(object_from_instance(<cEo *>lst.data))

View File

@ -20,10 +20,6 @@ from efl.c_eo cimport Eo_Class
from efl cimport Eina_List, const_Eina_List from efl cimport Eina_List, const_Eina_List
from libc.string cimport const_char from libc.string cimport const_char
cdef extern from "string.h":
void *memcpy(void *dst, void *src, int n)
char *strdup(char *str)
cdef class Eo(object): cdef class Eo(object):
cdef cEo *obj cdef cEo *obj
cdef readonly data cdef readonly data
@ -44,8 +40,8 @@ cdef char* _fruni(s)
cdef unicode _ctouni(const_char *s) cdef unicode _ctouni(const_char *s)
cdef const_char *_cfruni(s) cdef const_char *_cfruni(s)
cdef convert_array_of_strings_to_python_list(char **array, int array_length) cdef list convert_array_of_strings_to_python_list(char **array, int array_length)
cdef const_char ** convert_python_list_strings_to_array_of_strings(list strings) cdef const_char ** convert_python_list_strings_to_array_of_strings(list strings)
cdef convert_eina_list_strings_to_python_list(const_Eina_List *lst) cdef list convert_eina_list_strings_to_python_list(const_Eina_List *lst)
cdef Eina_List * convert_python_list_strings_to_eina_list(strings) cdef Eina_List * convert_python_list_strings_to_eina_list(strings)
cdef _object_list_to_python(const_Eina_List *lst) cdef list _object_list_to_python(const_Eina_List *lst)