Outil de débogage malloc

Le débogage des applications qui ne gèrent pas correctement la mémoire allouée par le sous-système malloc peut être difficile et fastidieux. En effet, il n'y a généralement pas de synchronicité entre l'insertion d'une erreur et l'exposition de son symptôme résultant.

S'ajoute à la difficulté la complexité inhérente à l'allocation de mémoire, avec des milliers d'allocations effectuées, annulées et accédées (peut-être) de manière asynchrone et simultanée, le tout dans un contexte multitâche qui nécessite une synchronisation robuste et efficace.

C'est pour ces raisons que l'objectif de nos outils de débogage est principalement de rapprocher le moment de la détection des symptômes du moment de l'insertion de l'erreur. Cela aide le développeur d'applications à identifier plus précisément quelle section de code est responsable de la validation de l'erreur.

De nombreux outils de débogage différents ont été développés pour une utilisation avec malloc. Certaines peuvent être utilisées en combinaison avec d'autres outils de débogage et avec toutes les règles d'allocation ; d'autres sont plus limitées dans leur utilisation. De nombreux outils de débogage consomment des ressources supplémentaires à celles requises par le processus. Il appartient au développeur d'applications de fournir des ressources adéquates lorsque cela est nécessaire.

Performance Considerations

Les outils de débogage malloc ne sont pas appropriés pour une utilisation à temps plein, constante ou à l'échelle du système. Bien qu'ils soient conçus pour un impact minimal sur les performances de l'application en cours de débogage, un impact négatif significatif sur le débit global du système peut se produire s'ils sont largement utilisés dans un système. En particulier, la définition de MALLOCDEBUG=catch_overflow dans le fichier /etc/environment n'est pas recommandée et risque de provoquer des problèmes système importants, tels qu'une utilisation excessive de l'espace de pagination. Les outils de débogage malloc ne doivent être utilisés que pour déboguer des applications uniques ou de petits groupes d'applications en même temps.

En raison du travail supplémentaire impliqué dans l'exécution de diverses vérifications d'exécution, les performances du sous-système malloc se dégradent de manière variable avec les outils de débogage malloc activés (en fonction de l'outil utilisé), mais pas au point que les applications deviennent inutilisables. Une fois le problème résolu, les outils de débogage malloc doivent être désactivés pour restaurer les performances du sous-système malloc .

Considérations relatives aux disques et à la mémoire

Lorsque les outils catch_overflow ou Malloc Log sont activés, le sous-système malloc consomme beaucoup plus de mémoire.

Pour catch_overflow, chaque demande malloc est augmentée de 4096 + 2 fois la taille de la longueur non signée, puis arrondie au multiple suivant de la macro PAGESIZE. catch_overflow peut s'avérer trop gourmande en mémoire à utiliser pour les applications de très grande taille, mais pour la majorité des applications nécessitant un débogage de la mémoire, l'utilisation supplémentaire de la mémoire ne doit pas poser de problème. Pour les applications de grande taille, l'utilisation des options debug_range et functionset sur catch_overflow peut réduire considérablement l'utilisation de la mémoire, ce qui permet de déboguer le programme au coup par coup.

Pour le journal malloc, un enregistrement d'allocation est stocké pour chaque allocation active du processus. Cette surcharge de la mémoire peut être réduite en spécifiant un faible nombre de pointeurs de pile sauvegardés.

Si l'application en cours de débogage appelle fréquemment des routines d'allocation de sous-système malloc , elle peut rencontrer des problèmes d'utilisation de la mémoire avec les outils de débogage malloc activés qui pourraient empêcher l'application de s'exécuter correctement dans un seul segment. Dans ce cas, il peut être utile de permettre à l'application d'accéder à de la mémoire supplémentaire à l'aide de la commande ulimit et de l'option -bmaxdata de la commande ld .

Pour l'exécution avec les outils de débogage malloc activés, définissez l'ulimit pour les variables data (-d) ) et stack (-s) ) comme suit :
ulimit -d unlimited
ulimit -s unlimited 

Pour réserver le maximum de 8 segments pour un processus 32 bits, l'option -bmaxdata doit être définie sur -bmaxdata:0x80000000.

Lorsque les outils de débogage malloc sont désactivés, les valeurs par défaut pour ulimit et -bmaxdata peuvent être restaurées.

Pour plus d'informations sur la commande ulimit et l'option -bmaxdata , voir Large Program Support.

Les outils de débogage malloc ne sont pas appropriés pour une utilisation dans certaines situations de débogage. Etant donné que certains outils malloc de débogage nécessitent la surcharge d'une page ou plus par allocation, les programmes qui émettent de nombreuses demandes d'allocation de petite taille verront leur utilisation de la mémoire augmenter considérablement. Ces programmes peuvent rencontrer de nouveaux échecs car les demandes d'allocation de mémoire sont refusées en raison d'un manque de mémoire ou d'espace de pagination. Ces échecs ne sont pas nécessairement des erreurs dans le programme en cours de débogage, et ils ne sont pas des erreurs dans l'outil malloc de débogage.

Un exemple spécifique est le serveur X, qui émet de nombreuses petites demandes d'allocation au cours de son initialisation et de son fonctionnement. Toute tentative d'exécution du serveur X à l'aide des commandes X ou xinit avec catch_overflow activé entraîne l'échec du serveur X en raison d'un manque de mémoire disponible. Il est cependant possible de déboguer X de façon fragmentaire à l'aide des options debug_range ou functionset. En général, les clients X ne rencontrent pas de problèmes fonctionnels lors de l'exécution avec catch_overflow activé. Pour utiliser catch_overflow sur un programme client X, procédez comme suit:
  1. Démarrez le serveur X avec catch_overflow désactivé.
  2. Démarrez une fenêtre de terminal (par exemple, dtterm, xterm, aixterm).
  3. Définissez les variables d'environnement appropriées dans la session de la fenêtre de terminal pour activer catch_overflow.
  4. Appelez le programme client X à déboguer à partir de la même fenêtre.

Activation du débogage malloc

Debug Malloc n'est pas activé par défaut, mais il est activé et configuré en définissant la variable d'environnement MALLOCDEBUG sur l'option appropriée. Si plusieurs options sont requises, elles peuvent être séparées par une virgule (,). Les options demandées en tandem doivent être compatibles entre elles.

Remarque: Pour désactiver le débogage malloc, annulez la définition de la variable d'environnement MALLOCDEBUG à l'aide de la commande unset MALLOCDEBUG .

Outils de débogage Malloc

Détection de dépassement de mémoire tampon

Les erreurs de gestion de la mémoire sont parfois causées par l'écriture du programme d'application après la fin d'une mémoire tampon allouée. Comme cela n'a souvent pas de conséquence immédiate, les symptômes ne se manifestent que beaucoup plus tard lorsque la mémoire qui a été écrasée (appartenant généralement à une autre allocation) est référencée et ne contient plus les données qui y étaient initialement stockées.

L'option de débogage catch_overflow permet aux utilisateurs d'identifier les écrasements de mémoire, les surcharges, les doublons libérés et la réutilisation de la mémoire libérée allouée par la sous-routine malloc . Les problèmes de mémoire détectés par l'outil catch_overflow entraînent un appel d'abandon ou une violation de segmentation (SIGSEGV). Dans la plupart des cas, lorsqu'une erreur est détectée, l'application s'arrête immédiatement et un fichier core est généré.

L'option catch_overflow affecte les allocations des stratégies et options d'allocation suivantes:
  • Règle d'allocation par défaut
  • Règle d'allocation Watson
  • Option multisegment de mémoire Malloc
  • Option de cache d'unités d'exécution Malloc
  • Option Disclaim Malloc

L'option de débogage catch_overflow est activée en définissant MALLOCDEBUG=catch_overflow. Cela active l'identification des écrasements et des écrasements de mémoire.

aligner

Par défaut, la sous-routine malloc renvoie un pointeur aligné sur une limite de 2 mots. Cela est nécessaire pour la conformité aux normes et pour les programmes qui ne peuvent pas accepter les accès non alignés à la mémoire (par exemple, les programmes utilisant des composants DCE). Toutefois, en raison d'un problème dans l'implémentation de l'option catch_overflow , il est possible qu'un programme écrase une mémoire tampon d'une quantité inférieure à la valeur d'alignement sans être détecté par catch_overflow. L'option align peut être utilisée pour indiquer au sous-système malloc de ne pas tenir compte de cet alignement par défaut afin de réduire ou d'éliminer le nombre d'octets par lesquels une mémoire tampon peut être écrasée sans détection. Un alignement personnalisé peut être spécifié pour toute puissance de deux entre 0 et 4096 inclus (par exemple 0,1,2,4, ...). Les valeurs 0 et 1 sont traitées de la même manière, c'est-à-dire qu'il n'y a pas d'alignement de la mémoire ; par conséquent, tout accès à la mémoire au-delà de la zone allouée provoquera un SEGFAULT.

L'option align fait partie de l'option catch_overflow et n'est significative que lorsque catch_overflow est activé. Pour activer un alignement autre que celui par défaut, définissez la variable d'environnement MALLOCDEBUG comme suit:
MALLOCDEBUG=catch_overflow,align:n
n est l'alignement souhaité.
Pour calculer le nombre d'octets de surcharges ou de surcharges que l'option catch_overflow autorise pour une demande d'allocation donnée lorsque n est l'alignement demandé et que la taille est le nombre d'octets à allouer, utilisez la formule suivante:
((((size / n) + 1) * n) - size) % n
L'exemple suivant illustre l'effet de l'option align sur la capacité de l'application à effectuer des écrasements ou des écrasements avec l'option catch_overflow activée. Dans cet exemple, l'option align est spécifiée avec la valeur 2:
MALLOCDEBUG=align:2,catch_overflow
L'option catch_overflow gère les dépassements et les écrasements comme suit:
  • Lorsqu'un nombre pair d'octets est alloué, malloc alloue exactement le nombre d'octets demandé, ce qui autorise 0 octet de surcharges ou de surcharges.
  • Lorsqu'un nombre impair d'octets est alloué, malloc alloue le nombre d'octets demandé, plus un octet supplémentaire pour satisfaire l'alignement requis. Cela permet d'obtenir 1 octet de surcharges ou de surcharges possibles.
override_signal_handling
L'option catch_overflow signale les erreurs de l'une des manières suivantes:
  • Les erreurs d'accès à la mémoire (telles que la tentative de lecture ou d'écriture après la fin de la mémoire allouée) provoquent une violation de segmentation (SIGSEGV), entraînant un vidage système.
  • Pour les autres types d'erreur (par exemple, la tentative de libération d'espace déjà libéré), l'option catch_overflow génère un message d'erreur, puis appelle la fonction d'abandon, qui envoie un signal SIGIOT pour mettre fin au processus en cours.

Si le programme appelant bloque ou intercepte les signaux SIGSEGV et SIGIOT, l'option catch_overflow ne peut pas signaler d'erreurs. L'option override_signal_handling permet de contourner cette situation sans recodage et régénération de l'application.

Si l'option override_signal_handling est spécifiée, l'option catch_overflow effectue les actions suivantes à chaque appel à une routine de sous-système malloc :
  1. Désactivez les gestionnaires de signaux existants définis par l'application pour SIGSEGV ou SIGIOT.
  2. Définissez l'action pour SIGIOT et SIGSEGV sur la valeur par défaut (SIG_DFL).
  3. Débloquez SIGIOT et SIGSEGV.

Si un gestionnaire de signaux d'application modifie l'action de SIGSEGV entre les appels de routine d'allocation de mémoire, puis tente un accès de mémoire non valide, l'option catch_overflow ne peut pas signaler l'erreur (l'application ne se ferme pas et aucun fichier core n'est généré).

Remarque :
  1. L'option override_signal_handling peut être inefficace dans un environnement d'application à unités d'exécution car l'option catch_overflow utilise la sous-routine sigprocmask et de nombreux processus à unités d'exécution utilisent la sous-routine pthread_sigmask .
  2. Si une unité d'exécution appelle la sous-routine sigwait sans inclure SIGSEGV et SIGIOT dans l'ensemble de signaux et que l'option catch_overflow détecte ensuite une erreur, l'unité d'exécution se bloque car l'option catch_overflow ne peut générer que SIGSEGV ou SIGIOT.
  3. Si un pointeur vers une mémoire non valide est transmis à une routine de noyau, celle-ci échouera et sera généralement renvoyée avec errno défini sur EFAULT. Si l'application ne vérifie pas le retour de l'appel système, cette erreur peut ne pas être détectée.
Plage de débogage

Par défaut, si l'option catch_overflow est activée, la détection de dépassement de mémoire tampon est effectuée pour chaque allocation du programme. Si l'option debug_range est spécifiée, seules les demandes d'allocation comprises entre une taille minimale et une taille maximale définies par l'utilisateur auront des dépassements de mémoire tampon détectés par l'option catch_overflow . Sinon, aucune détection de dépassement de mémoire tampon ne sera effectuée. Cette option permet à l'utilisateur de contrôler la quantité de ressources de mémoire supplémentaire consommée par l'option catch_overflow en utilisant uniquement l'outil dans des cas spécifiques.

L'option debug_range n'est significative que dans le contexte de l'option catch_overflow . Il est activé comme suit:
MALLOCDEBUG=catch_overflow,debug_range:min:max
min est la limite inférieure et max est la limite supérieure de la plage dans laquelle la détection de dépassement de mémoire tampon doit être effectuée. Si 0 est spécifié comme valeur minimale, toute valeur inférieure à la valeur maximale fera l'objet d'une détection de dépassement de mémoire tampon. Si 0 est spécifié comme valeur maximale, toute valeur supérieure à la valeur minimale fera l'objet d'une détection de dépassement de mémoire tampon.

Limitation: En raison d'une exigence d'implémentation interne, chaque allocation doit toujours avoir une taille de page d'au moins une longueur. Par conséquent, l'option debug_range réduit simplement le temps système de l'option catch_overflow au lieu de l'éliminer.

Si la sous-routine realloc est appelée avec une demande d'allocation comprise dans la plage spécifiée par l'utilisateur, la détection de dépassement de mémoire tampon est effectuée même si l'allocation d'origine n'était pas comprise dans la plage spécifiée. Le contraire est également vrai.

Remarque: Si l'option override_signal est définie avec l'option debug_range , le remplacement du comportement des signaux SIGIOT et SIGSEGV est effectué pour toutes les allocations.
ensemble de fonctions

En raison d'une exigence de mise en oeuvre interne, chaque allocation sera toujours nécessairement d'une longueur d'au moins une taille de page. Par conséquent, l'option functionset réduit simplement le temps système de l'option catch_overflow au lieu de l'éliminer.

Si la sous-routine realloc est appelée à partir d'une fonction qui est membre de la liste des fonctions spécifiées par l'utilisateur, la détection de dépassement de mémoire tampon est effectuée même si l'allocation d'origine n'a pas été effectuée à partir d'une fonction spécifiée. Le contraire est également vrai.

Remarque: Si l'option override_signal est définie avec l'option functionset , le remplacement du comportement des signaux SIGIOT et SIGSEGV est effectué pour toutes les allocations.

L'option functionset ne vérifie pas la validité des fonctions spécifiées dans la liste.

autoriser_sur-lecture

Par défaut, lorsque l'option de débogage catch_overflow est activée et que le programme appelant tente de lire après la fin de la mémoire allouée, une violation de segmentation se produit et le processus effectue un cliché du processus. Toutefois, il se peut que l'utilisateur ne soit pas intéressé par l'interception de ce type d'erreur et qu'il ait activé catch_overflow afin d'intercepter des écrasements plus dangereux. Si vous spécifiez l'option allow_overreading , l'option catch_overflow ignore les surcharges afin que d'autres types d'erreur, qui peuvent être considérés comme plus graves, puissent être détectés en premier.

L'option allow_overreading n'est significative que dans le contexte de l'option catch_overflow . Il est activé comme suit:
MALLOCDEBUG=catch_overflow,allow_overreading,
postfree_chèque

L'option postfree_checking consomme une quantité importante de mémoire supplémentaire. Les programmes dont les besoins en mémoire sont très importants risquent de ne pas pouvoir utiliser l'option postfree_checking .

Trace de malloc

Malloc Trace est une option de débogage conçue pour permettre le traçage de tous les appels à l'API du sous-système malloc via la fonction de trace du système.

Journal des erreurs

Malloc Log est une option de débogage conçue pour fournir à l'utilisateur une base de données d'exécution des allocations actives dans le sous-système malloc .

dotations de rapport

L'option report_allocations est un outil permettant de détecter les fuites de mémoire dans un programme d'application. L'option report_allocations utilise la base de données créée par Malloc Log pour générer une liste des allocations actuellement détenues par l'utilisateur. Un enregistrement de chaque allocation réussie est effectué au moment de la demande par le journal Malloc. Lorsqu'une allocation est libérée, Malloc Log supprime son enregistrement de la base de données. A la sortie du processus, la liste des allocations toujours actives est imprimée à stderr, ce qui donne une liste des allocations qui n'ont jamais été libérées par leurs appelants.

L'option report_allocations requiert la fonctionnalité de Malloc Log pour fonctionner. Par conséquent, le journal Malloc est implicitement activé lorsque report_allocations est activé. L'option report_allocations est activée comme suit:
MALLOCDEBUG=report_allocations
validate_ptrs

Par défaut, les API du sous-système malloc ne valident pas leurs pointeurs d'entrée pour s'assurer qu'elles référencent effectivement la mémoire précédemment allouée. Si l'un de ces pointeurs n'est pas valide, une altération grave du segment de mémoire peut se produire. Si vous spécifiez l'option validate_ptrs , les API du sous-système malloc effectuent une validation étendue sur leurs pointeurs d'entrée. Si un pointeur s'avère non valide (c'est-à-dire qu'il ne fait pas référence à la mémoire précédemment allouée par un appel à l'API du sous-système malloc ), un message d'erreur indiquant pourquoi il n'est pas valide est imprimé, la fonction d'abandon est appelée et un fichier core est généré. L'option validate_ptrs est similaire à la sous-option verbose . L'option validate_ptrs ne prend pas effet si l'option postfree_checking est activée.

L'option validate_ptrs est activée comme suit:
MALLOCDEBUG=validate_ptrs
Détection de malloc

Malloc Detect est une option de débogage conçue pour détecter et signaler l'altération des structures de données internes du sous-système malloc lors de chaque appel à une API de sous-système malloc .

verbose

Sous-option de Malloc Detect.

arène de contrôle

Sous-option de Malloc Detect.

sortie

Par défaut, les options de débogage malloc envoient leur sortie à stderr. Cela peut ne pas être souhaité pour tous les programmes. L'option output permet de fournir une autre destination pour les informations imprimées. La sortie peut être envoyée à stderr, stdout ou à n'importe quel fichier du système.

L'option output est activée comme suit:
MALLOCDEBUG=output:<filename>
poursuivre

De nombreuses options de débogage malloc appellent abort () lorsqu'elles détectent une erreur. Ce n'est pas toujours le comportement souhaité pour tous les programmes. L'option continue permet d'indiquer au sous-système malloc de continuer après la détection d'une erreur synchrone plutôt que d'abandonner le processus. Les messages d'erreur seront toujours consignés dans les canaux appropriés.

L'option continue est activée comme suit:
MALLOCDEBUG=continue
Remplissage de débogage malloc

Malloc debug fill est une option de débogage conçue pour remplir la mémoire allouée via les appels malloc () avec un modèle spécifié par l'utilisateur à des fins de débogage.

Le modèle doit être spécifié sous forme de chaîne (par exemple, export MALLOCDEBUG=fill:abc définit la mémoire allouée via malloc avec le modèle " abc) et un maximum de 128 caractères est autorisé. Si le modèle n'est pas spécifié, l'option de remplissage est ignorée.

L'option de remplissage de débogage malloc peut être activée comme suit:

MALLOCDEBUG=fill:pattern

Le modèle peut être un nombre octal ou hexadécimal spécifié sous la forme d'une chaîne. Par exemple, le modèle "\101" est traité comme la notation octale pour le caractère'A'et le modèle “\x41”est traité comme la notation hexadécimale pour le caractère'A'

Si un nombre octal non valide est spécifié, par exemple \777, qui ne peut pas être contenu dans 1 octet, sera stocké sous la forme \377, la valeur octale maximale pouvant être stockée sous la forme 1 octet.