9
votes

Test de l'unité pour Malloc échoué ()

Quelle est la meilleure façon pour les chemins de code de test d'unité impliquant un malloc () échoué () ? Dans la plupart des cas, cela n'a probablement pas d'importance parce que vous faites quelque chose comme xxx

mais dans certains cas, vous avez des choix autres que de mourir, car vous avez alloué des choses supplémentaires pour la mise en cache ou Quoi qu'il en soit, et vous pouvez récupérer cette mémoire.

Cependant, dans ces instances où vous pouvez essayer de récupérer à partir d'un malloc () que vous faites quelque chose de délicat et d'erreur sujette à un chemin de code assez inhabituel, ce qui fait Tests particulièrement importants. Comment allez-vous réellement faire cela?


3 commentaires

Vous pourriez détourner malloc () et le rendre aller 0 parfois.


De nombreuses fonctions de bibliothèque telles que printf sont peut échouer lorsque le processus est hors de mémoire.


@ephemient Qu'est-ce que ça va, si fprintf () gère correctement. ;-)


6 Réponses :


1
votes

dans FreeBSD i Une fois simplement surchargé de la bibliothèque C surchargé de la bibliothèque MALLOC.O (symboles de la faiblesse) et a remplacé la mise en œuvre MALLOC () avec une probabilité contrôlée d'échouer. J'ai donc lié statiquement et j'ai commencé à effectuer des tests. Srandom () a terminé la photo avec une séquence pseudo-aléatoire contrôlée.

Aussi regarder ici pour un ensemble de bons outils dont vous avez besoin à mon avis. Au moins ils surchargent MALLOC () / GRATUIT () pour suivre les fuites de sorte qu'il semble que l'utilisateur utilisable doit ajouter quelque chose que vous voulez.


0 commentaires

2
votes

C'est un peu brut, mais si vous voulez vraiment des tests unitaires, vous pouvez le faire avec #Ifdefs: xxx

Malheureusement, vous devez recompiler beaucoup avec cette solution.

Si vous utilisez Linux, vous pouvez également envisager d'exécuter votre code sous pression de mémoire en utilisant Ulimit , mais faites attention.


0 commentaires

16
votes

J'ai vu une solution cool à ce problème qui m'a été présenté par S. paavolainen. L'idée est de remplacer la norme malloc () , que vous pouvez faire juste dans la liaison, par un allocator personnalisé qui

  1. lit la pile d'exécution en cours de l'appel du fil malloc ()
  2. vérifie si la pile existe dans une base de données stockée sur le disque dur
    1. Si la pile n'existe pas, ajoute la pile à la base de données et renvoie null
    2. Si la pile existe déjà, alloue la mémoire normalement et retourne

      Ensuite, vous venez d'exécuter votre test de l'unité plusieurs fois: ce système énumère automatiquement via différents chemins de commande à Malloc () échec et est beaucoup plus efficace et fiable que par ex. Tests aléatoires.


4 commentaires

Nice répond. Ne comptra pas sur la chance de trouver des problèmes et vous permet de tester systématiquement les conséquences de l'échec de l'allocation.


+1 pour une couverture complète sur des tests aléatoires. SQLite fait quelque chose de similaire à ce sqlite.org/malloc.html#testing . Les défaillances MALLOC () sont déclenchées à l'aide d'un compteur au lieu de vérifier la pile pour l'unicité.


La théorie à ce sujet est solide et je voudrais mettre en œuvre cela. Votre réponse n'a pas vraiment eu des détails sur la mise en œuvre et une recherche de S. Paavolainen Malloc n'a rien soulevé non plus. Serait-il possible de fournir quelques détails d'implémentation?


J'ai fait une bibliothèque partagée qui implémente ce comportement. Il peut être utilisé sans modifier votre exécutable via LD_PRÉLOAD, tant que les symboles de débogage sont disponibles. Github.com/alight/mallocfail



2
votes

Je suggère de créer une fonction spécifique pour votre code MALLOC spécial que vous attendre pouvant échouer et que vous pourriez gérer gracieusement. Par exemple:

void* special_malloc(size_t bytes) {
  void* ptr = malloc(bytes);
  if(ptr == NULL) {
    /* Do something crafty */
  } else {
    return ptr;
  }
}


0 commentaires

2
votes

Écrivez votre propre bibliothèque qui implémente MALLOC en cas de défaillance aléatoire ou en appelant le véritable malloc (staticieusement lié ou explicitement dlopened)

puis ld_preload it


1 commentaires

J'ai fini par aller avec cette méthode. Il faut quelques drapeaux de compilation supplémentaires à utiliser avec mon cadre de test, mais c'est très flexible. De plus, dans ma bibliothèque d'objets partagés au lieu d'avoir échoué au hasard au hasard, j'ai déclaré une valeur globale qui ferait échouer au MALLOC lorsque j'ai spécifié. Cette variable devait être déclarée comme extern dans mon code de test.



1
votes

Vous pourriez accueillir MALLOC à l'aide de certains définies et de paramètres globaux pour le contrôler ... C'est un peu piraté, mais semble fonctionner.

#include <stdio.h>
#include <stdlib.h>

#define malloc(x) fake_malloc(x)

struct {
  size_t last_request;
  int should_fail;
  void *(*real_malloc)(size_t);
} fake_malloc_params;

void *fake_malloc(size_t size) {
  fake_malloc_params.last_request = size;
  if (fake_malloc_params.should_fail) {
    return NULL;
  }
  return (fake_malloc_params.real_malloc)(size);;
}

int main(void) {
  fake_malloc_params.real_malloc = malloc;
  void *ptr = NULL;
  ptr = malloc(1);
  printf("last: %d\n", (int) fake_malloc_params.last_request);
  printf("ptr: 0x%p\n", ptr);
  return 0;
}


0 commentaires