2010-05-19 12 views
1

(Note à l'intention des futurs lecteurs: L'erreur, sans surprise, est dans mon code et non std :: _ Rb_tree_rebalance_for_erase())Segmentation fault en fonction std std :: _ Rb_tree_rebalance_for_erase()

Je suis un peu nouveau à la programmation et je ne sais pas comment gérer une erreur de segmentation qui semble provenir d'une fonction std. J'espère que je fais quelque chose de stupide (c'est-à-dire, abuser d'un conteneur), parce que je n'ai aucune idée de comment le réparer.

L'erreur précise est

Programme signal reçu EXC_BAD_ACCESS, n'a pas pu accéder à la mémoire.
Raison: KERN_INVALID_ADDRESS à l'adresse: 0x000000000000000c
0x00007fff8062b144 dans std :: _ Rb_tree_rebalance_for_erase()
(gdb) backtrace
# 0 0x00007fff8062b144 dans std :: _ Rb_tree_rebalance_for_erase()
# 1 0x000000010000e593 dans la simulation de runEpidSim (ce = 0x7fff5fbfcb20) à stl_tree.h: 1263
# 2 0x0000000100016078 en main() à main.cpp: 43

la fonction qui sort juste avec succès avant que le défaut de segmentation met à jour le contenu de deux conteneurs. L'un est un boost::unordered_multimap appelé carriage; il contient un ou plusieurs objets struct Infection. L'autre conteneur est de type std::multiset< Event, std::less< Event > > EventPQ appelé ce.

void Host::recover(int s, double recoverTime, EventPQ & ce) { 

    // Clearing all serotypes in carriage 
    // and their associated recovery events in ce 
    // and then updating susceptibility to each serotype 
    double oldRecTime; 
    int z; 
    for (InfectionMap::iterator itr = carriage.begin(); itr != carriage.end(); itr++) { 
    z = itr->first; 
    oldRecTime = (itr->second).recT; 
    EventPQ::iterator epqItr = ce.find(Event(oldRecTime)); 
    assert(epqItr != ce.end()); 
    ce.erase(epqItr); 
    immune[ z ]++; 
    } 
    carriage.clear(); 
    calcSusc(); // a function that edits an array 
    cout << "Done with sync_recovery event." << endl; 
} 

La dernière ligne cout << apparaît immédiatement avant la faute de SEG.

Mon idée à ce jour est que le rééquilibrage est tentée sur ce immédiatement après cette fonction, mais je ne suis pas sûr pourquoi le rééquilibrage manquerait.


Mise à jour

J'ai confirmé la faute de seg en va (bien que le programme se bloque alors immédiatement pour d'autres raisons) lorsque je retire ce.erase(epqItr);. Je suis capable de supprimer des événements avec succès dans un autre endroit du code; le code que j'utilise là pour effacer des éléments dans ce est identique à ce qui est ici.

sanstracé rétrograde optimisation (grâce, BDK) révèle beaucoup plus d'informations:

Programme

signal reçu EXC_BAD_ACCESS, n'a pas pu accéder à la mémoire.
Raison: KERN_INVALID_ADDRESS à l'adresse: 0x000000000000000c
0x00007fff8062b144 dans std :: _ Rb_tree_rebalance_for_erase()
(gdb) backtrace
# 0 0x00007fff8062b144 dans std :: _ Rb_tree_rebalance_for_erase()
# 1 0x00000001000053d2 dans std :: _ Rb_tree, std: : moins,> std :: allocator> :: efface (this = 0x7fff5fbfdfe8, __position = {_ M_node = 0x10107cb50}) à> stl_tree.h: 1263
# 2 0x0000000100005417 dans std :: multiset, std :: allocator> :: effacer (this = 0x7fff5fbfdfe8, __position = {_ M_node = 0x10107cb50}) à stl_multiset.h: 346 # 3 0x000000010000ba71 dans la simulation de runEpidSim (ce = 0x7fff5fbfcb40) à Simulation.cpp: 426
# 4 0x000000010001fb31 en main() à main.cpp: 43

À moins Xcode est en train de lire les numéros de ligne mal, le seul stl_tree.h dans mon disque dur est vide sur la ligne 1263.

quelques personnes ont demandé à voir la fonction qui appelle récupérer. Il est un peu compliqué:

struct updateRecovery{ 
updateRecovery(int s, double t, EventPQ & ce) : s_(s), t_(t), ce_(ce) {} 
    void operator() (boost::shared_ptr<Host> ptr) { 
    ptr->recover(s_, t_, ce_); 
    } 
private: 
    int s_; 
    double t_; 
    EventPQ & ce_; 
}; 

// allHosts is a boost::multiindex container of boost::shared_ptr<Host> 
// currentEvents is the EventPQ container 
// it is an iterator to a specific member of allHosts 
allHosts.modify(it, updateRecovery(s, t, currentEvents)); 
cout << "done with recovery" << endl; 

Les dernières cout impressions. Le code a travaillé auparavant sans cette version particulière de la fonction de récupération.

Noah Roberts a à juste titre que le problème est à Simulation.cpp, ligne 426. saut ci-dessous pour une solution embarrassante.

+0

Qu'y a-t-il à stl_tree.h: 1263? –

+0

Le seul fichier stl_tree.h qui apparaît sur mon disque dur (également le seul fichier contenant '_Rb_tree_rebalance_for_erase' sur ma HD) est * vide * sur la ligne 1263 (?!). J'utilise gcc 4.2.1 (Apple build 5646) sur i686-apple-darwin10. La fonction rebalance_for_erase est définie sur les lignes 299-429. – Sarah

+1

Si vous mettez un cout dans le code appelant juste après l'appel de Host :: recover, cela s'imprime-t-il? En outre, essayez de compiler avec toutes les optimisations et inlining désactivées et vous pouvez obtenir une trace de pile plus utile – bdk

Répondre

3

Peut-être que vous tenez sur un iterator en ce à travers l'appel à récupérer. Si la récupération se produit pour supprimer cet élément, l'itérateur sera invalidé et toute utilisation future (par exemple une tentative d'effacement) pourrait entraîner une erreur de segmentation.

Il serait utile si nous pouvions voir plus de contexte de la façon dont ce est utilisé avant et après l'appel à récupérer.

+0

Vous avez raison! (J'ai besoin de regarder comment et quand le rééquilibrage des arbres se produit.) – Sarah

0

Peut-être que l'appel à assert n'est pas compilé avec votre configuration. Les affirmations dans le code de production sont généralement une mauvaise idée [TM].

Vous pouvez également outrepasserait immune « s limites de.

Essayez:

if (epqItr != ce.end()) 
    { 
     ce.erase(epqItr); 
     if (z is within immune's bounds) 
     { 
      ++immune[z]; 
     } 
    } 
1

Le problème est que sur la ligne 426 de Simulation.cpp, j'ai essayé de supprimer un événement dans le EventPQ currentEvents (ce a.k.a.) contenant que ma fonction recover() venait supprimé. L'itérateur avait manifestement été invalidé. Stupide.

Leçons:

  • débogage sur le code qui n'a pas été optimisé
  • Portez une attention particulière à ce que les cadres non liées std impliquent

Et pour l'avenir: la mémoire Trace dans valgrind

Je suis toujours perplexe pourquoi le débogueur m'a renvoyé à une ligne apparemment vide dans stl_tree.h.

J'ai une énorme appréciation ici pour les personnes qui m'ont aidé à travailler à travers cela. Je vais réviser ma question pour qu'elle soit plus concise pour les futurs lecteurs.

+1

C'est une règle générale à suivre lorsque vous rencontrez un crash. Regardez la callstack de haut en bas jusqu'à ce que vous frappiez votre propre code et commencez à y regarder. Généralement, vous constaterez que le bogue est provoqué quelque part dans cette pile dans votre propre code, pas dans la bibliothèque. Quand ce n'est pas le cas, vous trouverez généralement que vous avez frappé UB il y a une demi-heure et que vous êtes en train de courir dans tout ce que cela a causé. En fait, je n'ai jamais rencontré un bug de la bibliothèque. Courir dans beaucoup de bogues de compilateur mais je ne peux pas penser à n'importe quel bogue de bibliothèque. –