Question

Je travaille sur l'implémentation de la queue pour une mission. Je le fais fonctionner correctement mais il semble que je reçois une erreur de free à des moments aléatoires.

Je ne peux pas voir, il est cohérent de le retrouver dans un motif ou autre.

Par exemple, si j'appelle mon programme sous le nom "tail -24 test.in" Je voudrais obtenir l'erreur de la somme de contrôle incorrecte à la même ligne sur plusieurs exécutions. Cependant, avec différents fichiers et même un nombre différent de lignes à imprimer, je reviendrai sans erreur.

Toute idée sur la façon de dépister le problème, j'essaie de le déboguer pendant des heures sans résultat.

Voici le code incriminé:

lignes est défini comme un caractère ** et malloc était:

lines = (char**) malloc(nlines * sizeof(char *));

void insert_line(char *s, int len){

  printf("\t\tLine Number: %d Putting a %d line into slot: %d\n",processed,len,slot);
  if(processed > numlines -1){//clean up
    free(*(lines+slot));
    *(lines + slot) = NULL;
  }
  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
  strcpy(*(lines+slot),s);
  slot = ++processed % numlines;
}
Était-ce utile?

La solution

Votre routine écrit au-delà du tampon de ligne alloué.

La taille de la ligne passée sous forme d'argument (c'est-à-dire "len") n'inclut probablement pas le terminateur NUL. Lorsque vous appelez malloc pour copier la ligne (c.-à-d. "S"), vous devez attribuer un octet supplémentaire au terminateur de chaîne:

 *(lines + slot) = (char *) malloc((len + 1) * sizeof(char));

Autres conseils

Si vous pouvez reproduire le problème de manière cohérente avec des paramètres d'entrée spécifiques, procédez comme suit pour le débogage:

  • Commencez par déboguer vers le libre précis qui cause le problème.
  • Déterminez ensuite quand la mémoire sur le point d'être libre a été mallocée.
  • Ensuite, déboguez à l’endroit où la mémoire est mallocée.
  • Localisez dans le visualiseur de mémoire le bloc de mémoire alloué. Notez à la fois le début et la fin du bloc. Il existe probablement une valeur spéciale appelée guard block juste avant et juste après le bloc.
  • Maintenant, parcourez le code jusqu'à ce que la mémoire soit libérée. À un moment donné, votre code devrait écraser par erreur le bloc de protection. C'est la déclaration incriminée.

Notez que le problème pourrait très bien se situer dans une partie complètement différente de votre programme. Même si c’est ce libre qui signale l’erreur, le code qui écrase le bloc de protection peut être n’importe où.

Ma première question est la suivante: comment calculez-vous len? Est-ce simplement strlen ou cela inclut-il de la place pour le terminateur \ 0? Je pense que vous dépassez votre allocation dans votre stratégie. Mauvais comportement aura tendance à se produire sur les limites des mots et à apparaître au hasard. Vérifiez également que vos chaînes sources sont terminées par un octet nul. Si vous avez fait une erreur du côté de la lecture et que vous ne les avez pas terminées. Ensuite, strcpy peut écraser des choses de manière aléatoire.

  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
  strcpy(*(lines+slot),s);

Essayez peut-être:

  lines[slot] = (char *) malloc((len + 1) * sizeof(char));
  if(lines[slot] == NULL) exit(EXIT_FAILURE);
  if(strlen(s) <= len){
    strcpy(lines[slot],s);
  }
  else{
    /* do something else... */
  }

En termes de forme générale, je vous encourage également à apporter quelques modifications stylistiques pour rendre le tout un peu plus lisible, plus facile à suivre et plus résistant aux erreurs.

L'arithmétique des pointeurs est valide et amusante, mais je pense que votre intention est un peu plus claire si vous utilisez le tableau sous la forme suivante:

free(lines[slot]);
lines[slot] = NULL;

au lieu de

free(*(lines+slot));
*(lines + slot) = NULL;

Je vous encourage également à utiliser moins de statique. Il est assez facile de les traverser dans une structure de données et de les transmettre à vos accesseurs et à vos mutateurs. Il devient beaucoup plus clair où se passe l'action qui vous empêche de faire des choses comme:

static int numlines = 0;
void insert_line(char *s, int len){
    int numlines = 5;

où vous pouvez introduire des problèmes de portée qui sont simplement misérables à déboguer.

Les lignes et lignes ont-elles la même valeur?

L’appelant de insert_line laisse-t-il de la place pour le NUL final lorsqu’il passe la longueur dans le deuxième paramètre?

Je ne suis pas sûr que cela soit lié, mais ces deux lignes me semblent suspectes:

  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if((lines + slot) == NULL) exit(EXIT_FAILURE);

Vous affectez d’abord le retour de malloc à lignes [emplacement] , puis cochez (lignes + emplacement) , si ce dernier était NULL, vous avez déréférencé NULL. pointeur!

De même, si lines [slot] (votre * (lines + slot)) n'est pas null, vous perdrez de la mémoire lorsque vous lui affecterez le résultat de malloc ().

Je suppose que lignes est un caractère * lignes [] `et que l'emplacement est compris dans les limites autorisées!

Je suis d’accord avec les soupçons de Remo sur ces deux lignes, mais pas sur la tangente sur laquelle Remo a été appliquée. Nous devrions partager le crédit pour trouver ce bogue.

*(lines + slot) = some value
if((lines + slot) == NULL) then die
should be
if(*(lines + slot) == NULL) then die
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top