Historique de la question :
Rust a été conçu dès le départ comme un langage dont la priorité est la sécurité de la mémoire. Cependant, dans certaines tâches — par exemple, lors de l'interaction avec FFI ou les allocateurs de bas niveau — il est nécessaire d'utiliser des pointeurs bruts et de gérer la mémoire dynamique manuellement. Ces tâches se rencontrent aussi bien en programmation système que dans l'optimisation des performances. Il est donc important de savoir comment Rust prévient les fuites, les pointeurs pendants et les accès après libération.
Problème :
Les pointeurs bruts (*const T, *mut T) ne font pas partie du système de possession et de gestion des références de Rust : ils peuvent pointer vers une mémoire invalide, être libérés de manière incorrecte ou ne pas être libérés du tout. Une erreur dans leur manipulation peut entraîner un comportement indéfini (UB), des plantages, des vulnérabilités de sécurité ou des fuites de mémoire.
Solution :
Au lieu d'utiliser des pointeurs bruts, il est recommandé d'utiliser des types sûrs — Box, Rc, Arc, et pour les références temporaires — des références empruntées. Cependant, si l'utilisation de pointeurs bruts est inévitable (par exemple, pour travailler avec une API C), tout le travail doit être encapsulé dans des blocs unsafe, en organisant soigneusement le trait Drop, et en utilisant autant que possible des crates comme NonNull. Une autre technique consiste à utiliser des wrappers RAII et à minimiser le cycle de vie d'un pointeur.
Exemple de code :
fn allocate_in_heap() -> Box<i32> { Box::new(100) } // la mémoire sera libérée automatiquement // avec un pointeur brut unsafe fn leak_memory() { let ptr = libc::malloc(4) as *mut i32; if !ptr.is_null() { *ptr = 42; // libc::free(ptr); // si on oublie de libérer — fuite ! } }
Caractéristiques clés :
Le Box garantit-il le nettoyage automatique de toutes les valeurs imbriquées lors de la suppression de Box ?
Oui, lors de la suppression de Box<T>, le destructeur appelle d'abord le nettoyage de l'enveloppe elle-même, puis de manière récursive — de toutes les données imbriquées à l'intérieur (jusqu'aux éléments de Vec ou d'autres Box à l'intérieur de la structure T).
Peut-on transmettre en toute sécurité un pointeur brut d'une structure à travers plusieurs fonctions, sans risque d'accéder à une mémoire libérée ?
Non, le pointeur brut ne contient pas d'information sur la durée de vie de l'objet. Le compilateur ne peut pas vérifier la sécurité, donc la responsabilité incombe entièrement au développeur : si l'objet est libéré, le pointeur brut pointera vers le vide.
Si on utilise manuellement free ou drop_in_place, Rust peut-il appeler Drop deux fois pour la même adresse ?
Oui, si après une libération manuelle un autre Box/pointeur faisant référence à ce même bloc est laissé, alors lors de la destruction du second exemplaire, Drop sera appelé à nouveau, entraînant un comportement indéfini (UB). Il ne faut jamais libérer manuellement ce qui est géré par Box, Vec, etc.
Un programmeur a pris un pointeur brut d'une bibliothèque C externe, ne l'a pas libéré après utilisation ou perfnodo-dealloc a échoué avec le timing de la durée de vie.
Avantages :
Inconvénients :
Une enveloppe RAII avec Drop est utilisée, le pointeur est encapsulé avec Box ou NonNull, tout est détruit en toute sécurité à la fin de la portée.
Avantages :
Inconvénients :