Programmation C/C++ : les meilleurs bugs

noob4ever Message lu Posté le 29 Août 2008 à 11:34 Bulle
Avatar de noob4ever
Explorateur

Messages : 295
GCPoints : 48742
Ah oui là ok :lol: .
What did C:/DARTHVADER said to C:/DARTHVADER/LUKESKYWALKER ?

I'm your folder
Mod Message lu Posté le 07 Sep 2008 à 18:57 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
Allez, un autre que j'oublie deux fois sur trois : initialiser de fond en comble une structure à sa création.


Exemple dans mon cas : je créé un nouveau processus depuis une application parente. Processus qui doit utiliser DirectX, et donc créer une fenêtre pour y attacher l'objet Direct3D.

Problème : mon application créait bien la fenêtre (mais ne l'affichait pas), et l'initialisation Direct3D ne fonctionnait pas. Le tout sans retourner d'erreurs.

Solution : un petit coup de ZeroMemory sur la structure utilisée pour créer le processus, et hop, problème résolu :embarassed: .
Darktib Message lu Posté le 07 Sep 2008 à 20:10 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Ah, actuellement j'ai un bug plutot cocasse...

J'ai un vector nommé childs (pour le compilo de mon langage de scripts) de pointeurs...

A un moment, j'appelle une fonction qui est sensée appeler cette meme fonction mais chez tous les enfants (childs) puis effectuer ce quelle a a faire. Il y a un objet dans le tableau, je peut faire childs[0] (la méthode size() et tout le reste sont unanimes dessus...). Et bah manque de bol, je recois une segfault pour l'operateur []...

A détecter c'est facile... a résoudre... un peu moins... (d'ailleurs je ne l'ai pas toujours résolu^^ et j'espere le faire vite...)


Autant les strings de la stl c'est bien, mais les vectors ne valent pas ceux d'irrlicht je trouve
SEB Message lu Posté le 08 Sep 2008 à 15:28 Bulle
Avatar de SEB
Membre Evolué

Messages : 554
GCPoints : 103313

Citation :

Il y a un objet dans le tableau, je peut faire childs[0]



et alors? faire child de 0 ne veut pas dire qu'il y a un objet dedan surtout si comme tu l'as dit c'est un vector de pointeur....

il faudrait donc 1 que tu vérifie si les contenu ne sont pas NULL et ensuite mem si il ne sont pas nuls... que tes pointeurs d'objets ne sont pas obsolètes... Tu peu toujours résoudre ça en utilisant des smart pointers... mais personnellement j'aime pas trop ca lool ^^

Voilou voilou
++
Seb
NextGine : 3D games engine
Nombre de lignes actuel : 77683
Darktib Message lu Posté le 08 Sep 2008 à 20:08 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
bug résolu...

En fait, dans cette fonction je vérifie toujours les tableaux et tout ce qui est dans le vérifiable vu que je n'ai pas la performance pour objectif.


Citation :

si les contenu ne sont pas NULL et ensuite mem si il ne sont pas nuls... que tes pointeurs d'objets ne sont pas obsolètes


Ca c'est toujours vérifié, les conditions étant vraies.

Cela dit, mon bug s'est déplacé... c'était un petit vicieux en fait :wink:
Du coup j'ai un pointeur sur une classe... avec ce pointeur je peux récuperer les attributs publics mais pas appeler les methodes publiques... :strange: (encore des segfault...^^)
SEB Message lu Posté le 08 Sep 2008 à 21:32 Bulle
Avatar de SEB
Membre Evolué

Messages : 554
GCPoints : 103313
Est-ce que c'est une sous classe d'une hiérarchie? contenant par exemple des attributs dans une classe mère etc...???
NextGine : 3D games engine
Nombre de lignes actuel : 77683
Darktib Message lu Posté le 09 Sep 2008 à 18:21 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Voici la classe (un peu spéciale^^ - et j'ai changé le nom et simplifié la classe)

Code :
class myClass
{
public:
ctor;
dtor;

//fonctions
// la fonction qui plante :
virtual void recomputeOffset
{

for(unsigned int t = 0; t < childs.size(); t++)
{
childs[t]->recomputeOffset();
}

if(parent == 0)
{
offsetToParent = 0;
}
else
{
// Voila la ligne qui plante. L'appel de fonction déconne mais pas l'appel d'attribut...
offsetToParent = parent->totalChilds(parent->childNum)+1;
}

}

// un autre fonction
virtual unsigned int totalChilds(unsigned int from)
{
int offset = 0;

if(childs.size() == 0) return 0;
for(unsigned int t = from; t < childs.size(); t++)
{
offset += childs[t]->totalChilds(0);
offset++;
}

}

//attributs
myClass* parent;
std::vector<myClass*> childs;
unsigned int offsetToParent;
unsigned int childNum;
};


Voila en gros ma classe.

A noter que ce code n'est pas destiné a etre publié, du coup je respecte moins les regles d'encapsulation.
Dernière édition le 09 Sep 2008 à 18:21
dstar Message lu Posté le 10 Sep 2008 à 08:48 Bulle
Avatar de dstar
Explorateur

Messages : 56
GCPoints : 25718
Mouais...

Peut-être faudrait-il commencer par écrire un code correct:
- ton opération recomputeOffset n'a pas de liste de paramètres,
- ton opération totalChilds déclare retoruner un unsigned int mais ne possède pas d'instruction return à la fin, sauf dans le cas où il n'y a pas de fils.

dstar
dstar
Darktib Message lu Posté le 10 Sep 2008 à 15:44 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
pour le totalChilds c'est une erreur de recopiage, normalement elle retourne bien un unsigned int^^

Et sinon pourquoi des parametres pour recomputeOffset? Vu que ca calcule l'offset de la class en cours normalement les parametres seraient superflus...
Ah tu veux des parametres pour le parent... *vient de comprendre :absurd: ^^*
mouais...

Je peux toujours essayer^^
Dernière édition le 10 Sep 2008 à 15:45
dstar Message lu Posté le 10 Sep 2008 à 18:21 Bulle
Avatar de dstar
Explorateur

Messages : 56
GCPoints : 25718

Citation :

Et sinon pourquoi des parametres pour recomputeOffset? Vu que ca calcule l'offset de la class en cours normalement les parametres seraient superflus...
Ah tu veux des parametres pour le parent... *vient de comprendre :absurd: ^^*
mouais...



Euh non, ce n'est pas ce que je voulais dire... en général, quand une opération ne possède pas de paramètre, on met quand même une liste vide (). Mais ce n'est certainement pas la cause de ton bug.

J'ai relu tes posts précédents et je vois que tu parles d'un segmentation fault. En général, sur les systèmes Unix (dont Linux), un segmentation fault est synonyme d'un pointeur NULL. Et le bus error induit l'utilisation d'une adresse mémoire invalide (hors espace d'adressage).

dstar
dstar
Darktib Message lu Posté le 10 Sep 2008 à 19:46 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
En fait tu m'a mis sur la voie... j'ai mis le parent en parametre et maintenant ca marche nickel - donc merci pour ton aide - et ma scepticité ne m'a servie a rien^^.

Sinon je suis sous Windows pour les tests... mais normalement mais librairie devrait etre portable.

Eu
Citation :

h non, ce n'est pas ce que je voulais dire... en général, quand une opération ne possède pas de paramètre, on met quand même une liste vide (). Mais ce n'est certainement pas la cause de ton bug.



Le 'on' qui rajoute la liste vide, c'est nous ou le compilateur? Et qu'est-ce que la liste vide en question?

Sinon pour la segfault, le pointeur a NULL est aussi vrai pour windows; mais en plus -je ne suis pas sur- il me semble que la segfault sur windows englobe aussi le bus error de linux.

Mais ce que par contre je ne comprend pas c'est que ca plantait que pour les méthodes et pas les attributs...
dstar Message lu Posté le 11 Sep 2008 à 10:07 Bulle
Avatar de dstar
Explorateur

Messages : 56
GCPoints : 25718

Citation :

Le 'on' qui rajoute la liste vide, c'est nous ou le compilateur? Et qu'est-ce que la liste vide en question?



Le 'on', c'est le stanard ANSI C++. Quand une fonction C++ (qu'elle soit membre de classe ou non) ne prend pas de paramètre, on se doit de mettre, après le nom de la fonction, une parenthèse ouverte suivie d'une parenthèse fermée. Il est possible d'ajouter le mot clef void, ça sert pour la compatibilité avec le C.
Mais en aucun, le standard ne permet de déclarer une fonction en écrivant le nom et en ouvrant directement le corps de la fonction, comme tu l'as fait avec ta fonction recomputeOffset.

Tu as écrit:
Code :
void recomputeOffset
{
...
}


là où tu aurais dû écrire:
Code :
void recomputeOffset()
{
...
}


ou à la limite:
Code :
void recomputeOffset(void)
{
...
}



Certains compilateurs l'acceptent, mais ce n'est pas standard. Dans tous les cas, ce n'est certainement pas la cause de ton bug.

D'après ce que tu décris, c'est probablement le membre parent de ta classe qui possédait une valeur erronnée quand l'opération recomputeOffset était appelée.

dstar
dstar
Darktib Message lu Posté le 11 Sep 2008 à 21:07 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
ah je vois ce que tu veux dire... pour l'histoire des parametres c'est une erreur de copie, jamais gcc n'accepterait un truc pareil^^

Sinon pour la valeur erronée... c'est a mon avis ce qui s'est passé. Mais je ne comprend toujours pas le bug : il n'arrivait que lorsque le fait d'avoir des enfants se reproduisait + de 2 fois, et uniquement quand la fonction n'avait pas de grands-parents... et evidemment que pour les méthodes...


Finalement je penche pour peut etre une erreur compilo.
dstar Message lu Posté le 12 Sep 2008 à 09:12 Bulle
Avatar de dstar
Explorateur

Messages : 56
GCPoints : 25718

Citation :

Finalement je penche pour peut etre une erreur compilo.



:lol:, je parie ce que tu veux que ce n'est pas un problème de compilateur. Les erreurs de compilateurs C++, ça n'existe pratiquement plus aujourd'hui, enfin, sauf si tu utilises un outil exotique.

dstar
dstar
Mod Message lu Posté le 12 Sep 2008 à 14:07 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
Hum, en effet, des bugs de compilateur C ou C++, faut vraiment les chercher. Car heureusement pour nous, tout le monde n'est pas de chez TGC.
Darktib Message lu Posté le 12 Sep 2008 à 19:59 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
:lol:
Ben gcc m'avait quand meme généré une dll trop grosse a mes débuts d'IA::Astar - ce qui la ralentissait considérablement.
Ensuite est-ce que vous pouvez expliquer en s'appuyant sur le standard ISO C++ pourqoi avec le meme pointeur on ne peut appeller que les attributs et pas les méthodes???

Sans réponse, j'ai choisi l'option la plus facile :lol: . L'autre - erreur humaine - me parait improbable (:lol:).

edit : :je viens d'exploser mes statistiques en matiere de smiley lol dans un message^^
Dernière édition le 12 Sep 2008 à 20:00
dstar Message lu Posté le 12 Sep 2008 à 23:35 Bulle
Avatar de dstar
Explorateur

Messages : 56
GCPoints : 25718

Citation :

Ensuite est-ce que vous pouvez expliquer en s'appuyant sur le standard ISO C++ pourqoi avec le meme pointeur on ne peut appeller que les attributs et pas les méthodes???



Bon, j'explique.

Dans le cas d'un attribut, l'adresse de l'attribut par rapport à l'adresse de base de l'objet est constante. Ca signifie qu'à partir de l'adresse de l'objet, le compilateur met en place un calcul simple (une addition) pour calculer l'adresse de l'attribut.

Dans le cas d'une méthode virtuelle appelée à partir d'un pointeur ou d'une référence, c'est bien plus compliqué (ce n'est pas le cas pour les méthodes qui ne sont pas virtuelles). Ceci vient du fait que le compilateur doit mettre en place une liaison dynamique.
En effet, le type réel d'un objet peut être différent du type du pointeur ou de la référence servant à référencer l'objet, ça s'appelle le polymorphisme d'objet. L'adresse de la méthode C++ à appeler est dépendante du type réel de l'objet et non du type du pointeur ou de la référence utilisée pour faire l'appel. Et le compilateur ne peut connaître, au moment de la compilation l'adresse de la méthode à appeler.
Une liaison dynamique consiste pour le compilateur à mettre un descripteur de classe, pour chaque classe, qui contient l'adresse des méthodes virtuelles. Lors de l'appel à une fonction virtuelle, au lieu de sauter directement à l'adresse de la méthode, l'application doit d'abord accéder à ce descripteur pour déterminer l'adresse à laquelle sauter (en général, l'adresse du descripteur de la classe d'un objet est stockée 4 octets avant l'adresse de base de l'objet).

Dans le cas où une application possède un bug qui corrompt une partie de la mémoire, il est possible que le descripteur d'une classe soit affectée sans que la valeur des attributs de ses instances ne le soient.

dstar
dstar
Darktib Message lu Posté le 13 Sep 2008 à 18:23 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Merci pour l'explication :smile: ( qui d'ailleurs a l'avantage d'etre tres claire).

Donc ca voudrait dire que le descripteur de la classe est modifié... peut etre alors parce ce que cette classe "s'appelle" soit-meme. C'est ballot.

Donc comme ca la prochaine fois je mettrait des pointeurs en arguments^^

je me coucherait moins bete ce soir :proud: :absurd:
Répondre
GameCorp - Site d'apprentissage et d'entraide à la création de jeux vidéo.
XHTML Valid 1.1 - Page générée en 0.3066 secondes