2010-10-15 15 views
1

Je suis tombé sur un bug plutôt charmant que j'essaye d'enrouler ma tête autour. J'ai l'impression d'avoir déjà vu ça auparavant, mais cette fois je veux comprendre pourquoi cela se passe.Pourquoi ma valeur n'augmentera-t-elle pas? Mémoire piétinant/pépin de pile?

I ont:

int i; 
int debug = 0; 
for(i = 0; i < buf_end; i++) { 
    do_some_buffer_work(); 
    if(something_is_true()) { 
     do_something_important(); 
     printf("debug is %i, i is %i", debug++, i); 
    } 
} 

printf ("fin \ n");

et je reçois en sortie:

debug is 1, i is 55 
debug is 2, i is 55 

donc il y avait un point où la boucle a été exécuté deux fois avec la même valeur pour i. rien que je fais dans la boucle touche directement i. De plus, je doute que ce soit la mémoire traditionnelle qui piétine, car la valeur est toujours la même. Je me doutais bien qu'il avait quelque chose à l'origine du compteur de programme pour se déplacer (car parfois avec le mauvais vous reliant obtenir des bugs similaires,) jusqu'à ce que je l'ai fait le test suivant:

int i; 
static int debug; 
for(i = 0; i < buf_end; i++) { 
    do_some_buffer_work(); 
    if(something_is_true()) { 
     do_something_important(); 
     printf("debug is %i, i is %i\n", debug++, i++); 
     printf("debug is %i, i is %i\n", debug++, i++); 
     printf("debug is %i, i is %i\n", debug++, i++); 
    } 
} 
printf("end\n"); 

et je suis cette sortie intéressante:

debug is 0, i is 55 
debug is 1, i is 56 
debug is 2, i is 57 
debug is 3, i is 55 
debug is 4, i is 56 
debug is 5, i is 57 
end 

Donc ici il est évident que deux itérations complètes avec le même j'ai exécuté, mais la variable de débogage n'a pas été affectée. Il semblerait que la valeur soit mise en cache et restaurée pour une raison quelconque. J'ai eu un pressentiment et changé la variable de débogage à la non-statique et obtenu ceci:

int i; 
int debug = 0; 
for(i = 0; i < buf_end; i++) { 
    do_some_buffer_work(); 
    if(something_is_true()) { 
     do_something_important(); 
     printf("debug is %i, i is %i\n", debug++, i++); 
     printf("debug is %i, i is %i\n", debug++, i++); 
     printf("debug is %i, i is %i\n", debug++, i++); 
    } 
} 
printf("end\n"); 

et je suis cette sortie intéressante:

debug is 0, i is 55 
debug is 1, i is 56 
debug is 2, i is 57 
debug is 0, i is 55 
debug is 1, i is 56 
debug is 2, i is 57 
end 

Il semble donc que les variables qui vivent sur la pile sont réinitialisé au début de la 55e itération. Je suis sûr que le bug est dans un de ces appels do_something_important() - qui traitent de la lecture du tampon - mais ce bug a pris un caractère qui lui est propre et je pense que je dois un peu de respect pour en savoir plus sur sa nature avant de l'écraser. Donc, s'il vous plaît plutôt que d'essayer de m'aider à le réparer, faites-moi savoir si vous avez une idée de la raison pour laquelle cela se produit. Plus précisément, que peut-on changer dans l'état du programme pour «réinitialiser» des valeurs comme celle-ci? Edit: Je suis désolé si les gens sont agacés que j'ai laissé de côté les fonctions. Ils sont assez volumineux et ont des références à d'autres fonctions, mais la principale raison pour laquelle je l'ai laissée de côté est que je ne me soucie pas de résoudre ce problème; Je veux savoir comment je pourrais le recréer le plus simplement possible. 2e édition: Voici la fonction immédiate où les bleus se produisent. Y compris la fonction référencée et toutes les sous-fonctions et définitions est probablement autour de 500 lignes donc je ne le fais pas ici.

static int find_headers_search(FCALParseContext *fpc, uint8_t *buf, int buf_size, 
           int search_start) 

{ 
    FCALFrameInfo fi; 
    int end_offset = -1, size = 0, i; 
    uint8_t *header_buf; 

    int debug = 0; 
    for (i = 0; i < buf_size - 1; i++) { 
     if ((AV_RB16(buf + i) & 0xFFFE) == 0xFFF8) { 
       av_log(NULL,AV_LOG_DEBUG,"predebug%i i %i\n",debug, i); 
      header_buf = fcal_fifo_read_wrap(fpc, search_start + i, 
              MAX_FRAME_HEADER_SIZE, 
              &fpc->wrap_buf, 
              &fpc->wrap_buf_allocated_size); 

      if (frame_header_is_valid(header_buf, &fi)) { 
       av_log(NULL,AV_LOG_DEBUG,"frame num %u bufstart %u, size %u, end %u i %i\n", (unsigned int)fi.frame_or_sample_num, 
         search_start, buf_size, search_start + buf_size -1, i); 
       FCALHeaderMarker **end_handle = &fpc->headers; 

       size = 0; 
       while (*end_handle) { 
        end_offset = (*end_handle)->offset; 
        end_handle = &(*end_handle)->next; 
        size++; 
       } 

       *end_handle = av_mallocz(sizeof(FCALHeaderMarker)); 
       if (!*end_handle) { 
        av_log(fpc->avctx, AV_LOG_ERROR, 
          "couldn't allocate FCALHeaderMarker\n"); 
        return AVERROR(ENOMEM); 
       } 
       (*end_handle)->fi  = fi; 
       (*end_handle)->offset = search_start + i; 
       /* The actual size of the linked list is now size + 1 */ 
       update_sequences(fpc, size - FCAL_MAX_SEQUENTIAL_HEADERS, 
           FFMIN(size, FCAL_MAX_SEQUENTIAL_HEADERS), 
           *end_handle); 
       fpc->nb_headers_found++; 
       size++; 
       av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++); 
       size = 0; 
       while (*end_handle) { 
        end_offset = (*end_handle)->offset; 
        end_handle = &(*end_handle)->next; 
        size++; 
       } 

       *end_handle = av_mallocz(sizeof(FCALHeaderMarker)); 
       if (!*end_handle) { 
        av_log(fpc->avctx, AV_LOG_ERROR, 
          "couldn't allocate FCALHeaderMarker\n"); 
        return AVERROR(ENOMEM); 
       } 
       (*end_handle)->fi  = fi; 
       (*end_handle)->offset = search_start + i; 
       /* The actual size of the linked list is now size + 1 */ 
       update_sequences(fpc, size - FCAL_MAX_SEQUENTIAL_HEADERS, 
           FFMIN(size, FCAL_MAX_SEQUENTIAL_HEADERS), 
           *end_handle); 
       fpc->nb_headers_found++; 
       size++; 
       av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++); 
       av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++); 
       av_log(NULL,AV_LOG_DEBUG,"debug%i i %i\n",debug++, i++); 
      } 
     } 
    } 
    return size; 
} 
+3

Eh bien, vous êtes presque certainement en train de jeter la pile dans l'une de vos fonctions appelées. Sans vrai code, il n'est plus possible d'en dire plus. Le conseil serait d'utiliser un débogueur pour regarder 'debug', et ensuite de passer à travers jusqu'à ce qu'il change de façon inattendue. –

+0

Merci. Je devrais préciser que je veux juste savoir comment battre la pile comme ça. Que dois-je faire pour obtenir un résultat similaire? –

+1

@fsmc: Déclare un tableau sur la pile et écris la fin. –

Répondre

0

Le problème était dû à la réévaluation d'une fonction d'effets secondaires avec une macro MAX (a, b). Il était dans le code client à cette fonction.

3

Il y a un tampon, il y a un buf_end, il y a un 'travail de tampon'. Tout invisible dans l'extrait. Clairement, il y a un code invisible qui écrit après la fin de la mémoire tampon, écrasant les variables locales debug et i. Définissez un point d'arrêt de données à la fin du tampon et vous le trouverez généralement dans une minute ou deux.

+0

Mais, s'il écrasait les variables locales, je ne m'attendrais pas à ce qu'il finisse toujours par être les mêmes valeurs au début de l'itération. –

+0

@fsmc: Tout ce que quelqu'un ici peut faire c'est deviner! Avez-vous déjà essayé le débogage? –

+0

Pourquoi supposez-vous que le piétinement n'est pas répétable? Pourquoi supposez-vous que ce n'est pas? Ce sont des questions stupides, utilisez le débogueur. –

2

Cela ressemble à la récursivité/réentrance pour moi. L'hypothèse suivante expliquerait le comportement observé:

do_some_buffer_work() sous certaines conditions appelle la fonction contenant ce code. Cela expliquerait la cohérence de l'état statique et le redémarrage des locaux. La raison pour laquelle vous ne le voyez que pour certaines valeurs de i est que something_is_true() n'est vrai que pour les valeurs de i.

Vous devriez probablement mettre le code dans votre débogueur. L'observation de la pile d'appels à un point de rupture sur votre printf() déterminera rapidement si la récursivité s'est produite.

+0

La réentrance sonne comme le mot juste. Qu'est-ce qui peut provoquer cela? –

+0

Le premier extrait de code impliquerait que cela n'est pas dû à la récursivité; 'debug' est incrémenté. –

+0

@Oli: Bon point; mais vu le brutal élidage du code, je pense que tous les paris sont désactivés sur le code affiché étant forcément le code exécuté! – Clifford

1

Cela peut ou ne pas être utile (ne pas savoir quoi que ce soit sur ce que do_some_buffer_work(), something_is_true(), ou do_something_important() fait du genre entrave l'analyse un peu). mais peut essayer d'avoir deux contre boucle variables dans différents endroits et vérifier quand ils diffèrent:

int i; 
static int ii; 

int debug = 0; 
for(i = 0, ii = 0; i < buf_end; i++, ii++) { 
    if (i != ii) debugBreak(); 

    do_some_buffer_work(); 
    if (i != ii) debugBreak(); 

    if(something_is_true()) { 
     if (i != ii) debugBreak(); 
     do_something_important(); 
     printf("debug is %i, i is %i", debug++, i); 
    } 

    if (i != ii) debugBreak(); 
} 

Cela pourrait vous donner un contexte plus proche quand les choses vont mal.