Erreur double free or corruption en C++

Muhammad Husnain 12 octobre 2023
  1. Allocation et désallocation dynamiques de mémoire en C++
  2. double libre ou corruption Erreur en C++
  3. Comment éviter l’erreur double free or corruption en C++
Erreur double free or corruption en C++

Ce didacticiel abordera les problèmes qui se produisent dans les allocations de mémoire dynamiques en C++. Lors de l’utilisation de la mémoire de tas, nous rencontrons de nombreux problèmes qu’il est très important de résoudre lors de la gestion de la mémoire de tas.

Tout d’abord, nous verrons comment nous allouons de la mémoire et les différentes méthodes fournies en C++ ; ensuite, nous nous dirigerons vers les causes et les solutions de l’erreur double free or corruption en C++.

Allocation et désallocation dynamiques de mémoire en C++

C++ nous permet d’allouer de la mémoire de variable ou de tableau pendant l’exécution. C’est ce qu’on appelle l’allocation de mémoire dynamique.

Dans d’autres langages de programmation, tels que Java et Python, le compilateur maintient automatiquement la mémoire des variables. Cependant, ce n’est pas le cas en C++.

En C++, nous devons libérer manuellement la mémoire allouée dynamiquement une fois que nous n’en avons plus besoin. Nous pouvons allouer et désallouer dynamiquement de la mémoire en utilisant les fonctions new et delete.

Il existe deux autres fonctions, à savoir malloc et free, qui sont également incluses dans C++ pour l’allocation et la désallocation dynamiques de la mémoire.

Prenons un exemple ci-dessous démontrant l’utilisation des fonctions new et delete.

#include <iostream>
using namespace std;

int main() {
  int* ptr;
  ptr = new int;
  *ptr = 40;
  cout << *ptr;
  delete ptr;
  return 0;
}

Nous avons alloué dynamiquement de la mémoire pour une variable int en utilisant l’opérateur new. Il est intéressant de noter que nous avons utilisé la variable de référence ptr pour allouer dynamiquement de la mémoire.

L’opérateur new renvoie l’adresse de l’emplacement mémoire. Dans le cas d’un tableau, l’opérateur new renvoie l’adresse du premier élément du tableau.

Nous pouvons désallouer la mémoire utilisée par une variable déclarée dynamiquement après que nous n’avons plus besoin de l’utiliser. L’opérateur delete est utilisé pour cela.

Il rend la mémoire au système d’exploitation. C’est ce qu’on appelle la désallocation de mémoire.

L’exemple suivant vous montrera une démonstration des fonctions malloc et free.

#include <cstdlib>
#include <iostream>
using namespace std;

int main() {
  int* ptr2 = (int*)malloc(sizeof(int));
  *ptr2 = 50;

  cout << *ptr2;
  free(ptr2);
  return 0;
}

En C++, la méthode malloc() affecte un pointeur sur un bloc de mémoire non initialisé. Le fichier d’en-tête cstdlib le définit.

malloc prend en paramètre la taille de la mémoire que vous devez allouer et renvoie un pointeur void pointant vers le bloc de mémoire alloué. Par conséquent, il peut être typé selon nos besoins.

D’autre part, la méthode free() désalloue la mémoire allouée à l’aide de la fonction malloc. Il renvoie cette mémoire au système d’exploitation et évite les problèmes de fuite de mémoire.

double libre ou corruption Erreur en C++

Des erreurs double-free se produisent lorsque free() est utilisé plus d’une fois avec la même adresse mémoire comme entrée.

Appeler free() deux fois sur la même variable peut entraîner une fuite de mémoire. Lorsqu’un logiciel exécute deux fois free() avec le même paramètre, les structures de données de gestion de la mémoire dans l’application sont corrompues, permettant à un utilisateur malveillant d’écrire des valeurs dans n’importe quelle zone de la mémoire.

Cette corruption peut entraîner le blocage du programme ou modifier le flux d’exécution dans certains cas. Un attaquant peut inciter un programme à exécuter un code de son choix en écrasant des registres ou des régions de mémoire spécifiques, ce qui se traduit par un shell interactif avec des droits élevés.

Une liste chaînée de tampons libres est lue lorsqu’un tampon est free() pour réorganiser et combiner les morceaux de mémoire libre (pour allouer des tampons plus grands à l’avenir). Ces morceaux sont organisés dans une liste à double lien avec des liens vers les morceaux avant et après eux.

Un attaquant peut écrire des valeurs arbitraires en mémoire en déliant un tampon inutilisé (ce qui se produit lorsque free() est invoqué), en écrasant efficacement des registres précieux et en lançant un shellcode depuis son tampon.

Prenons un exemple ci-dessous.

#include <cstdlib>
#include <iostream>
using namespace std;

int main() {
  int* ptr2 = (int*)malloc(sizeof(int));
  *ptr2 = 50;

  cout << *ptr2;
  free(ptr2);
  free(ptr2);
  return 0;
}

Production:

free(): double free detected in cache 2
Aborted

Dans l’extrait de code ci-dessus, nous avons utilisé la fonction free() deux fois, ce qui signifie que nous essayons de libérer la mémoire qui est déjà libre et qui n’est plus allouée. Cela crée un problème de fuite de mémoire et est à l’origine du plantage du code.

Il existe également de nombreuses autres situations qui peuvent rencontrer de telles erreurs. Mais il existe trois raisons courantes (et souvent superposées) pour les vulnérabilités à double libération.

  1. Conditions d’erreur et autres situations inhabituelles
  2. Une fois l’espace mémoire libéré, il est utilisé.
  3. Confusion sur quelle section du programme est en charge de la libération de la mémoire

Bien que certaines vulnérabilités double-free ne soient pas beaucoup plus complexes que l’exemple précédent, la plupart d’entre elles sont réparties sur des centaines de lignes de code ou même sur plusieurs fichiers. Les programmeurs semblent être particulièrement enclins à libérer plusieurs fois des variables globales.

Comment éviter l’erreur double free or corruption en C++

Ce type de vulnérabilité peut être évité en affectant NULL à notre pointeur chaque fois qu’il devient libre (c’est-à-dire que la mémoire pointée par ce pointeur se libère). Ensuite, la plupart des gestionnaires de tas ignorent les pointeurs nuls libres.

Il est recommandé de mettre à zéro tous les pointeurs supprimés et de vérifier si la référence est null ou non avant de la libérer. Au début de notre code, nous devons initialiser le pointeur null avant d’utiliser ce pointeur dans tous les cas.

Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn

Article connexe - C++ Error