Question

C'est un peu hypothétique et grossièrement simplifié mais...

Supposons un programme qui appellera des fonctions écrites par des tiers.Ces parties peuvent être considérées comme non hostiles mais ne peuvent pas être considérées comme « compétentes ».Chaque fonction prendra des arguments, aura des effets secondaires et renverra une valeur.Ils n’ont pas d’État tant qu’ils ne courent pas.

L'objectif est de s'assurer qu'ils ne peuvent pas provoquer de fuites de mémoire en enregistrant tous les mallocs (et autres), puis en libérant tout après la fermeture de la fonction.

Est-ce possible?Est-ce pratique ?

p.s.La partie importante pour moi est de garantir qu'aucune allocation ne persiste, donc les moyens de supprimer les fuites de mémoire sans le faire ne me sont pas utiles.

Était-ce utile?

La solution

Vous ne spécifiez pas le système d'exploitation ou l'environnement, cette réponse suppose Linux, glibc et C.

Vous pouvez définir __malloc_hook, __free_hook et __realloc_hook pour pointer vers les fonctions qui seront appelées respectivement depuis malloc(), realloc() et free().Il existe une page de manuel __malloc_hook montrant les prototypes.Vous pouvez ajouter des allocations de piste dans ces hooks, puis revenir pour laisser la glibc gérer l'allocation/désallocation de mémoire.

Il semble que vous souhaitiez libérer toutes les allocations en direct lorsque la fonction tierce revient.Il existe des moyens pour que gcc insère automatiquement des appels à chaque entrée et sortie de fonction en utilisant -finstrument-functions, mais je pense que ce serait inélégant pour ce que vous essayez de faire.Pouvez-vous demander à votre propre code d'appeler une fonction dans votre bibliothèque de suivi de la mémoire après avoir appelé l'une de ces fonctions tierces ?Vous pourrez alors vérifier s'il existe des allocations que la fonction tierce n'a pas déjà libérées.

Autres conseils

Tout d'abord, vous devez fournir les points d'entrée pour malloc() et free() et amis.Parce que ce code est déjà compilé (n'est-ce pas ?), vous ne pouvez pas compter sur #define pour rediriger.

Ensuite, vous pouvez les implémenter de manière évidente et enregistrer qu'ils proviennent d'un certain module en liant ces routines à ces modules.

Le moyen le plus rapide consiste à pas de journalisation du tout. Si la quantité de mémoire qu'ils utilisent est limitée, pourquoi ne pas pré-allouer tout le « tas » dont ils auront besoin et écrire un allocateur à partir de cela ?Puis quand c’est fait, libérez tout le « tas » et le tour est joué !Vous pouvez étendre cette idée à plusieurs tas si c'est plus complexe que cela.

Si vous avez vraiment besoin de vous « connecter » et de ne pas créer votre propre allocateur, voici quelques idées.Premièrement, utilisez une table de hachage avec des pointeurs et un chaînage interne.Une autre solution serait d'allouer un espace supplémentaire devant chaque bloc et d'y placer votre propre structure contenant, par exemple, un index dans votre "table de journal", puis de conserver une liste libre d'entrées de table de journal (sous forme de pile pour en obtenir une gratuite). ou en remettre un gratuit est O(1)).Cela prend plus de mémoire mais devrait être rapide.

Est-ce pratique ?Je pense que oui, à condition que le speed-hit soit acceptable.

Vous pouvez exécuter les fonctions tierces dans un processus distinct et fermer le processus lorsque vous avez fini d'utiliser la bibliothèque.

Une meilleure solution que d'essayer de consigner les mallocs pourrait être de mettre les fonctions en sandbox lorsque vous les appelez : leur donner accès à un segment fixe de mémoire, puis libérer ce segment une fois l'exécution de la fonction terminée.

Une utilisation non confinée et incompétente de la mémoire peut être tout aussi dommageable qu’un code malveillant.

Ne pouvez-vous pas simplement les forcer à allouer toute leur mémoire sur la pile ?De cette façon, il serait garanti d'être libéré après la sortie de la fonction.

Dans le passé, j'ai écrit une bibliothèque de logiciels en C dotée d'un sous-système de gestion de la mémoire permettant de consigner les allocations et les libérations, ainsi que de faire correspondre manuellement chaque allocation et chaque libération.Cela s'est avéré utile pour tenter de détecter des fuites de mémoire, mais son utilisation s'est avérée difficile et longue.Le nombre de journaux était écrasant et il fallait beaucoup de temps pour les comprendre.

Cela étant dit, si votre bibliothèque tierce dispose d'allocations étendues, il est probablement peu pratique de suivre cela via la journalisation.Si vous utilisez un environnement Windows, je vous suggère d'utiliser un outil tel que Purify[1] ou BoundsChecker[2] qui devrait être capable de détecter les fuites dans vos bibliothèques tierces.L’investissement dans l’outil devrait être rentabilisé grâce au temps gagné.

[1]: http://www-01.ibm.com/software/awdtools/purify/ Purifier

[2]: http://www.compuware.com/products/devpartner/visualc.htm Vérificateur de limites

Puisque vous vous inquiétez des fuites de mémoire et que vous parlez de malloc/free, je suppose que vous êtes en C.Je suppose également, sur la base de votre question, que vous n'avez pas accès au code source de la bibliothèque tierce.

La seule chose à laquelle je peux penser est d'examiner la consommation de mémoire de votre application avant et après l'appel, de consigner les messages d'erreur s'ils sont différents et de convaincre le fournisseur tiers de réparer les fuites que vous trouvez.

Si vous avez de l'argent à dépenser, envisagez d'utiliser Purify pour suivre les problèmes.Cela fonctionne à merveille et ne nécessite ni code source ni recompilation.Il existe également d'autres bibliothèques malloc de débogage moins chères.La clôture électrique est un nom dont je me souviens.Cela dit, les hooks de débogage mentionnés par Denton Gentry semblent également intéressants.

Si vous êtes trop pauvre pour Purify, essayez Valgrind.C'est bien mieux qu'il y a 6 ans et beaucoup plus facile à approfondir que Purify.

Microsoft Windows fournit (utilisez SUA si vous avez besoin d'un POSIX), très probablement, l'infrastructure tas + (autre API connue pour utiliser le tas) la plus avancée de tous les systèmes d'exploitation disponibles aujourd'hui.

les hooks de débogage __malloc() et les interfaces de débogage CRT associées sont utiles dans les cas où vous disposez du code source des tests, mais ils peuvent souvent manquer les allocations par les bibliothèques standard ou tout autre code lié.Ceci est attendu car il s’agit de l’infrastructure de débogage du tas de Visual Studio.

drapeaux est un ensemble très complet et détaillé de fonctionnalités de débogage incluses avec Windows depuis de nombreuses années.Avoir des fonctionnalités avancées pour les cas d'utilisation source et binaire uniquement (car il s'agit de l'infrastructure de débogage du tas du système d'exploitation).

Il peut enregistrer les traces complètes de la pile (repagination des informations symboliques lors d'une opération de post-traitement) de tous les utilisateurs du tas, pour tous les points d'entrée de modification du tas, en série si nécessaire.En outre, il peut modifier le tas avec des cas pathologiques qui peuvent aligner l'allocation des données de telle sorte que la protection des pages offerte par le système VM soit attribuée de manière optimale (c'est-à-direallouez le bloc de tas demandé à la fin d'une page, de sorte que même un débordement d'un seul octet soit détecté au moment du débordement.

umdh est un outil qui peut aider à évaluer l'état à différents points de contrôle, mais les données sont continuellement accumulées pendant l'exécution de la cible. Il ne s'agit pas d'un simple arrêt de débogage par points de contrôle dans le contexte traditionnel.Aussi, AVERTISSEMENT, La dernière fois que j'ai vérifié, la taille totale du tampon circulaire qui stocke les informations de la pile, pour chaque requête, est quelque peu petite (64 000 entrées (entrées + pile)), vous devrez donc peut-être effectuer un vidage rapide pour les gros utilisateurs de tas.Il existe d'autres moyens d'accéder à ces données, mais umdh est assez simple.

NOTE il y a 2 modes ;

  1. MODE 1, umdh {-p:Process-id|-pn:ProcessName} [-f:Filename] [-g]
  2. MODE 2, umdh [-d] {Fichier1} [Fichier2] [-f:Nom du fichier]

    Je ne sais pas quelle folie a saisi le développeur qui a choisi d'alterner entre le spécificateur d'argument -p:foo et l'ordre nu des arguments, mais cela peut devenir un peu déroutant.

Le SDK de débogage fonctionne avec un certain nombre d'autres outils, instantané de mémoire est un outil qui se concentre apparemment sur les fuites de mémoire et autres, mais je ne l'ai pas utilisé, votre kilométrage peut varier.

Exécutez gflags sans arguments pour le mode UI, les +arg et /args sont différent "modes" d'utilisation également.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top