C++ segmentation fault sur une list stl - comment trouver le probleme?

Bonjour

J’utilise les listes de la librairie standar c++, et a un moment je me retrouve avec un segmentation fault lorsque j’essaye d’inserer un element (push_back et push_front pareil).
Pourtant tout marche bien peandant un bon moment, j’ai une liste de pas mal d’elements et d’un coup ca bloque.

J’ai essayé de catcher les exception voir si je fait pas une erreur quelque part, donc a chaque fois que je fais une operation sur ma liste (push_back, erase…) je fait ca :

try{
operation_sur_ma_liste
}
catch(…){
afficher exception
}

et je n’ai aucune exception qui se declenche et toujours un segmentation fault au meme endroit.

Comment savoir ce qui produit cette erreur?

merci

Si tu as une seg fault: soit ta liste n’est pas déclarée, soit l’objet que tu veux insérer n’existe pas…

Une idée pour localiser l’erreur c’est de mettre des messages

cout<<"Insertion…"<<endl;
l.push_back(…);
cout<<"OK"<<endl;

j’ai fait ca!
et juste avant de faire l’insertion je fait un affichage de sa taille et size_max (j’ai de la marge).

donc je suis sur qu’elle existe, et je suis sur que l’erreur de segmentation est au moment ou je veut faire l’insertion.

Et c’est une liste d’int… j’ai affiché l’int que je veut inserer et il existe.

Essaye ça :

#define DEBUG(x) {std::clog << #x << std::endl; x;}

Et met le sur chacune de tes lignes. Ca plantera en t’affichant la ligne. Sinon gdb + bt fera tout aussi bien l’affaire (et c’est moins fastidieux). Sinon la taille n’a normalement rien à voir vu que la liste grandit en conséquence (-> std::list::push_back)

Tu fais quoi comme opérations?

j’ai deja fait quelque chose du genre (j’ai mis des cout que j’ai deplacé jusqu’a touvrer sur quelle ligne ca plante). Donc je sais precisement ou ca plante : lorsque je fait un push_back. J’ai mis un cout juste avant et juste apres et seul mon premier cout est affiché.

Je sais que la liste grandit en conséquence mais j’ai affiché la taille max pour voir si j’avais pas un probleme de memoire.

Les opération que je fait sont :
erase et push_back c’est tout. Puis des parcours de liste classique avec des iterateurs

Et sans les erases?

ca marche mais le probleme c’est que du coup je sais pas si le probleme viens d’un erase car d’enlever les erase modifie completement ma liste.

Et si le probleme viens d’un erase il devrai pas me le signaler avec le catch exception?

Affiche un peu le code.

Ton problème doit se jouer avec les itérateurs. J’espère que ton code ressemble pas à :

typedef std::list<int> intlist; 
intlist l;
intlist::iterator it = l.begin();

l.push_back(0);
l.push_back(0);
l.push_back(0);
l.erase(it);
l.push_back(0);

Car ton problème doit certainement lié au fait que l’itérateur que tu utilises est d’une certaine façon invalide.

Alors, je suis dans une classe.
j’ai declaré ma liste comme membre private de cette classe :
std::list <int> CC;

et voila la fonction que j’apelle lorsque je veut supprimer un element (je recherche le minimum, mais pas le minimum de ma liste car ce sont en fait des index qui correspondent a des valeur dans un tableau) :

Erf; Non je ne trouve pas d’erreur logique. Tu devrais y aller avec gdb (en faisant un break au niveau du try) et voir ce qu’il fait exactement.

Sinon petite remarque : ++tempIterator c’est mieux au niveau perf.

Je me suis mis a gdb et voila ce que j’obtient :

Breakpoint 4, Graphe::addToCC (this=0xbffa2f94, v=99696) at Graphe.cc:184
184                     CC.push_back(10);
(gdb) print CC
$1 = {<std::_List_base<int,std::allocator<int> >> = {
    _M_impl = {<std::allocator<std::_List_node<int> >> = {<__gnu_cxx::new_allocator<std::_List_node<int> >> = {<No data fields>}, <No data fields>},
      _M_node = {_M_next = 0x8118ce0, _M_prev = 0x8223608}}}, <No data fields>}

et ca plante comme ca :

Program received signal SIGSEGV, Segmentation fault.
0xb7ddfc64 in free () from /lib/tls/i686/cmov/libc.so.6

qu’est ce que je peut faire pour trouver ou est le probleme?
J’ai essayé push_front et push_back font la meme erreur de segmentation fault et si j’enleve un element de la liste (pop_back) la il ne fait plus le segmentation fault a cet endroit.

Essaye un bt pour voir la pile.

Sinon, tu peux voir ce qui merde avec p : tente des trucs genre *CC._M_node._M_next

Mais pour moi c’est lié à un problème avec ton erase() : d’une façon ou d’une autre, tu casse le maillon.


(gdb) bt
#0  Graphe::addToCC (this=0xbf88c074, v=99696) at Graphe.cc:184
#1  0x080516e8 in Graphe::dijkstra (this=0xbf88c074, vertex=0, distances=0xb7727008) at Graphe.cc:60
#2  0x08049728 in setPath (g=@0xbf88c074, path=0x859dad0, nbPoints=3) at visualizeGeodesics.cc:279
#3  0x0804a920 in main (argc=4, argv=0xbf88c6d4) at visualizeGeodesics.cc:95

(gdb) p CC._M_impl._M_node._M_next
$3 = (std::_List_node_base *) 0x8118ce0
(gdb) p *CC._M_impl._M_node._M_next
$4 = {_M_next = 0x89f0b58, _M_prev = 0xbf88c094}
(gdb) p 0x89f0b58
$5 = 144640856
(gdb) p 0xbf88c094
$6 = 3213410452

bon ca me dis rien de plus je vais voir si je trouve quelque chose du coté du erase

vu que je ne vois pas d’erreur non plus dans mon erase, quel test je peux faire pour savoir si mon iterateur est invalide au moment ou je fait le erase, ou si je fais une erreur?

si j’efface le premier element de ma liste a chaque fois (cc.begin) au lieu de chercher le minimum ca fonctionne.

Donc ca doit venir comme le disai sans-nom d’un erase avec un mauvais iterateur.

Mais je n’arrive pas a trouver la faille.

Alors comment mettre un test pour voir quand l’iterateur est mauvais?
Ou comment faire pour catcher une exception a ce moment la?

j’ai essayé ca mais ca ne donne rien :


	try {
  CC.erase( minIterator );
	}
	catch(...) {
  std::cout<<"exception : "<<std::endl;
  exit(0);
	}

je retire ce que j’ai dis :
j’ai le meme segmentation fault en faisant des erase(CC.begin())

donc ca ne vient pas de mon erase.

voici le bt :


#0  0xb7dc8c64 in free () from /lib/tls/i686/cmov/libc.so.6
#1  0xb7dca83f in malloc () from /lib/tls/i686/cmov/libc.so.6
#2  0xb7f7a4b7 in operator new () from /usr/lib/libstdc++.so.6
#3  0x0804b05a in __gnu_cxx::new_allocator<std::_List_node<int> >::allocate (this=0xbfea4eb4, __n=1)
    at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/ext/new_allocator.h:88
#4  0x0804b07d in std::_List_base<int, std::allocator<int> >::_M_get_node (this=0xbfea4eb4)
    at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:316
#5  0x0804b092 in std::list<int, std::allocator<int> >::_M_create_node (this=0xbfea4eb4, __x=@0xbfea4c54)
    at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:448
#6  0x0804b0f2 in std::list<int, std::allocator<int> >::_M_insert (this=0xbfea4eb4, __position={_M_node = 0xbfea4eb4}, __x=@0xbfea4c54)
    at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:1139
#7  0x08052722 in std::list<int, std::allocator<int> >::push_back (this=0xbfea4eb4, __x=@0xbfea4c54)
    at /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:761
#8  0x08051132 in Graphe::addToCC (this=0xbfea4e94, v=107506) at Graphe.cc:201
#9  0x08051830 in Graphe::dijkstra (this=0xbfea4e94, vertex=0, distances=0xb7797008) at Graphe.cc:60

pourquoi il fait un free quand je fait un push_back?

Tu peux essayer avec autre chose que des entiers? Genre un objet avec un destructeur?

Mais bon, à mon avis tu es tombé sur une version moisie de la stl :slight_smile:

(ceci dit, m’en sert pas des masses, mais mes erases ont toujours fonctionnés sur des listes, pour le peu que je me suis servi, en tout cas erase(begin()) marchait)

pourtant j’ai les llibraires fournis avec ma kubuntu donc ce sont les dernieres versions qui doivent marcher a peu pres bien…

Un truc encore plus bizarre : Je cree une nouvelle liste juste avant l’endroit ou j’ai l’erreur de segmentation et je lui fait un push_front d’un nombre et j’ai une erreur de segmentation sur cette nouvelle liste.

:ouch:

Hum.

J’ai bien une distrib ubuntu sous VMWare. Je veux bien tester et regarder ça ce WE, car ça m’intrigue :slight_smile: (et comme ça ça améliore mon C++ ))

A tout hasard, ton code semble venir d’un tout. As tu essayer de faire une test avec juste la liste d’entier et rien d’extérieur (de toi donc)?

Si jamais ça marche, alors j’arrêterai les recherches sur la stl : suppose que quelques part tu tape au mauvais endroit (exemple: tu prends l’adresse de la référence sur entier renvoyé, que tu décrémente de 1, et tu change la valeur => pan!).

Ca y est j’ai trouvé le problème.
Par contre je comprend pas pourquoi ca s’est manifesté lors de la manipulation de la liste.

Voila ce qu’il se passait :
Je cree un objet Graphe (dans lequel il y a ma liste), puis un tableau d’entier dynamique (avec l’operateur new). Et il se trouve qu’a l’execution du programme ce tableau etait de taille 3 alors qu’il etait censé etre beaucoup plus grand (je m’etait trompé de variable).
Ensuite je remplissai ce tableau avec des -1 pour l’initialiser. Et la ca ne posait pas de problème alors que je remplissai plus de 100k cases dans un tableau de 3 cases. Deja je comprends pas pourquoi j’ai pas eu de segmentation fault a ce moment la.
Et pourquoi je l’ai eu plus tard lors de l’execution de la classe graphe et de la manipulation de sa liste.

En plus, pour essayer de detecter ce genre d’erreur j’ai utilisé Valgrind, et il ne m’a rien detecté du tout…