3 votes

Dois-je libérer la mémoire retournée par une fonction C appelée via CFFI ?

J'ai cet exemple de code qui a une fonction text() renvoyant une chaîne nouvellement allouée :

ffi_test = FFI()
ffi_test.set_source('_test', '''
char* test() { return strdup("hello world"); }
''')
ffi_test.cdef('''
char* test();
void free(void *);
''')
ffi_test.compile(verbose=True)

Cela fonctionne bien :

In [1]: from _test import ffi, lib
In [2]: x = lib.test()
In [3]: ffi.string(x)
Out[3]: b'hello world'
In [4]: lib.free(x)

Cependant, je n'ai pas pu trouver dans la documentation si je dois ou non manuellement free() la chaîne retournée de si CFFI prend la propriété du pointeur dès qu'il est retourné au code Python.

Aussi, si je dois manuellement free() est-ce que je dois exposer free() dans mon cdefs ou est-ce que le CFFI fournit une façon plus agréable de le faire ?

5voto

Antti Haapala Points 11542

À partir de la documentation sur Travailler avec des pointeurs, des structures et des tableaux y en citant la bonne section :

Toute opération qui, en C, renverrait un pointeur, un tableau ou un type de structure vous donne un objet cdata frais. Contrairement à l'"original", ces nouveaux objets cdata n'ont pas de propriété.

Vous devez donc le libérer, il n'a aucun moyen d'en assumer la propriété : En C, il y a beaucoup de fonctions qui renvoient un pointeur vers un objet chaîne constante en mémoire que non seulement il n'est pas alloué dynamiquement, mais qu'il n'est pas alloué ou modifiable du tout, par exemple. Les libérer serait très erroné.


Aussi pour free la documentation indique ce qui suit :

Une alternative consiste à déclarer et à appeler les fonctions C malloc() et free(), ou une variante comme mmap() et munmap(). Vous contrôlez alors exactement quand la mémoire est allouée et libérée. Par exemple, ajoutez ces deux lignes à votre ffibuilder.cdef() existant :

void *malloc(size_t size);
void free(void *ptr);

Comme il est très important que le correct Bibliothèque standard C free est utilisé pour un pointeur renvoyé par strdup vous ne pouvez pas compter sur CFFI pour faire magiquement la bonne chose, mais au lieu de cela, comme vous le soupçonnez, vous devez exposer free() . Vous pouvez également utiliser le gc comme suggéré par Barmar pour enregistrer un nettoyage automatique, si nécessaire :

x = ffi.gc(x, lib.free)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X