Forum Programmation.c++ Segmentation fault incomprehensible

Posté par  .
Étiquettes :
0
30
nov.
2006
Bonjour,


J'ai code un programme en c++, faisant appel a diverses librairies codees en C, C++ et fortran77. La compilation se passe a merveille, et l'appliccation tourne a merveille, sauf a un endroit.

il s'agit de 6 boucles imbriquees dans le genre


for (p.p6=p.lbm;p.p6<=p.lbM;p.p6=p.p6+p.lbs)
for (p.p5=p.tbm;p.p5<=p.tbM;p.p5=p.p5+p.tbs)
for (p.p3=p.A0m;p.p3<=p.A0M;p.p3=p.p3+p.A0s)
for (p.p1=p.m0m;p.p1<=p.m0M;p.p1=p.p1+p.m0s)
for (p.p2=p.mhm;p.p2<=p.mhM;p.p2=p.p2+p.mhs)
{
subroutine_quelconque // execution du programme
}


ou tous les parametres sont stockes dans une classe appelee p. p.xxm, p.xxM et p.xxs sont respectivement la limite inferieure, superieure et l'increment pour chaque parametre (xx valant respectivement m0, A0, mh, tb et lb).


Tout marche bien jusqu'a ce que les parametres p1,p2,p3,p5,p6 prennent les valeurs suivantes
p1 = 100, p2 = 1300, p3 = 4000, p5 = 55, p6 = 0
(resultat venant de gdb) .

La, paf, segfault !


Du coup je change les bornes des boucles histoire de tester uniquement le point qui foire, et la surprise ! Le programme se termine super bien ! et retourne la bonne valeur apres execution de subroutine_quelconque.


Est-ce que quelqu'un aurait une idee d'ou pourrait venir le plantage ?


D'avance merci


Benj


PS: desole, mais je n'ai pas d'accents sur mon clavier :p
  • # suppositions...

    Posté par  . Évalué à 2.

    ca marche bien si tu reduis certaines limites ?
    donc en gros avec les valeurs par defaut tu sature quelques part ta machine..
    • [^] # Re: suppositions...

      Posté par  . Évalué à 1.

      au moment de traiter l'element :
      p1 = 100, p2 = 1300, p3 = 4000, p5 = 55, p6=0

      soit le 55x4000x100x1300 = 28.600.000.000e element
      si tu fais des pas de 1 dans tes boucles
      • [^] # Re: suppositions...

        Posté par  . Évalué à 1.

        comme je l'ai dit plus bas, j'ai environ 20000-30000 elemts dans mes loops. donc je ne pencherais pas trop pour la saturation ...
  • # Débordement de tableau ?

    Posté par  . Évalué à 6.

    Tout marche bien jusqu'a ce que les parametres p1,p2,p3,p5,p6 prennent les valeurs suivantes

    p1 = 100, p2 = 1300, p3 = 4000, p5 = 55, p6 = 0

    Un tel plantage (segmentation fault lors de la manipulation de pointeurs pointant dans des tableaux) est souvent dû à un débordement des tableaux en question. D'où la question : ces valeurs sont-elles dans les bornes de tes tableaux (ou des espaces mémoire alloués dynamiquement) ?

    En passant, en C, pour un tableau de taille N (i.e. dont les indices valides vont de 0 à N-1 inclus), le fait même de calculer l'adresse du pseudo-élément d'indice supérieur à N cause un comportement indéfini (*). Si la même chose est valable en C++ (je n'en sais rien), alors il est possible que tes incrémentations pi += pasi débordent les tableaux, et que cela suffise à causer un plantage.

    Plus concrètement : si on suppose
    int array[10];
    p.mhm=&array[0];
    p.mhM = 10;
    p.mhs = 3;
    Alors, lors de la boucle for (p.p2=p.mhm;p.p2<=p.mhM;p.p2=p.p2+p.mhs) { /* ... */ }, p.p2 prendra les valeurs &array[0], &array[3], &array[6], &array[9] sans problème. Puis, à la fin de la 4e itération, l'incrément affectera la valeur "&array[12]", qui est invalide. En C, le comportement indéfini surviendrait ici, et se manifesterait probablement par un segmentation fault sur ton système.

    A toi de voir si ton code permet d'être dans une telle situation, et si le comportement indéfini s'applique aussi en C++.

    (*) Le calcul de l'adresse du pseudo-élément d'indice N est par contre bien défini, c'est une exception tolérée pour faciliter les traitements de tableaux par pointeurs. Par contre, essayer d'accéder (en lecture ou en écriture) au contenu de ce pseudo-élément (qui n'existe pas) cause un comportement indéfini. Tout ceci est valable en C, je le rappelle ; je ne sais pas si ça concerne aussi le C++.
    • [^] # Re: Débordement de tableau ?

      Posté par  . Évalué à 2.

      je peux pas plusser, mais l'explication est claire et probablement que le probleme vient de là.

      bravo...
      • [^] # Re: Débordement de tableau ?

        Posté par  . Évalué à 1.

        En fait je n'ai pas de tableaux.... Quand ma sous-routine quelconque a terminee, elle ecrit le resultat dans un fichier. Et donc pas de risque de depassement de tableaux. Au passagem je n'ai qu'environ 20000-30000 points dans mes loops, donc je ne pense pas que ela soit un probleme de memoire physique (j'ai verifie avec free -t apres chaque iteration, et tout va bien)

        En jouant avec gdb, j'ai finalement identifie d'ou venait le probleme... d'une des libraries fortran (donc je ne suis peut-etre plus dan le bon forum ... je vais neanmoins exposer le probleme):


        xx0 = dmin1(mn(1),mn(2),mn(3),mn(4))
        xx1 = dmax1(mn(1),mn(2),mn(3),mn(4))
        idummy = 1
        do i = 1,4
        if(mn(i).eq.xx0)then
        iord(1) = i
        elseif(mn(i).eq.xx1)then
        iord(4) = i
        else
        irem(idummy) = i
        idummy = idummy+1
        endif
        enddo

        if(mn(irem(1)).le.mn(irem(2)))then

        [...]




        et irem(2) vaut 1060472881 (et mn va de 1 a 4...), d'ou le segmentation fault.

        par contre je ne comprends pas du tout comment irem(2) peut prendre cette valeur. Dams mon cas mn(1)=xx0 et mn(4)=xx1, donc je devrais avoir iord(1)=1, iord(4)=4,irem(1)=2 et irem(2)=3. Ce qui est le cas, sauf pour irem(2) !
        • [^] # Re: Débordement de tableau ?

          Posté par  . Évalué à 3.

          Du peu que je peux deviner de ma non-connaissance du fortran, les irem() semblent être assignés aux indices des 2 éléments mn() qui ne sont ni le min, ni le max.
          Mais que se passe-t-il si tous les mn() sont égaux, ou qu'au moins 2 valeurs soient égales au min ou au max ? Dans ce cas seuls le 1er ou les 2 premiers "if" seront valides, et le else final ne sera jamais pris, ou pris 1 seul fois. irem(2), voire irem(1) ne sera jamais affecté et restera égal à la valeur de la case mémoire où il se trouve, donc aléatoire.

          Vérifie que ce cas particulier est bien traité dans ton code. Par exemple, change ta routine fortran pour tester si idummy vaut bien 3 à la fin, et sinon quitte en affichant toutes tes valeurs mn(); tu devrais voir la cause du problème.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.