Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion: Héritage qui bug

  1. #1
    Membre régulier
    Avatar de alpha_one_x86
    Profil pro
    Développeur informatique
    Inscrit en
    décembre 2006
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : décembre 2006
    Messages : 394
    Points : 112
    Points
    112

    Par défaut Héritage qui bug

    Bonjour,

    TransferThreadAsync hérite de TransferThread.
    Quand j'appelle realByteTransfered() d'un objet TransferThreadAsync, https://github.com/alphaonex86/Ultra...hread.cpp#L652
    Il appelle TransferThread::destinationExists() https://github.com/alphaonex86/Ultra...hread.cpp#L249 ... soit une autre fonction de la classe parente. Confirmer par le stack de gdb.
    J'ai vérifié avec valgrind, rien.

    Pour reproduire il faut juste lancer une copie de fichier avec ultracopier, et mettre un breakpoint sur TransferThread::destinationExists()
    Ca fait une semaine que je suis bloquer la dessus.

    Cordialement,
    Developpeur d'Ultracopier et Supercopier
    CatchChallenger, mmorpg old school hautes performances, insensible aux latences, support de i2p/tor, multiple gameplay.

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    Consultant informatique
    Inscrit en
    octobre 2004
    Messages
    11 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : octobre 2004
    Messages : 11 109
    Points : 27 268
    Points
    27 268

    Par défaut

    Salut,

    Et, le problème, c'est ???

    Parce que là, je ne vois rien d'anormal, dans le fait qu'une fonction (redéfinie dans une classe dérivée) fasse appel à une fonction de la classe de base...

    Et il serait même tout à fait logique que cette fonction (destinationExists) ne soit absolument pas virtuelle Car, quelle que soit la sorte de transfert envisagée, il semble en effet tout à fait logique que l'on commence par s'inquiéter de savoir si la destination existe, tu ne penses pas

    Donc, si tu pouvais nous indiquer ce que tu estimes être le problème, ou, je sais pas, moi, le symptôme observé du problème, cela pourrait nous faciliter énormément la vie
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre régulier
    Avatar de alpha_one_x86
    Profil pro
    Développeur informatique
    Inscrit en
    décembre 2006
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : décembre 2006
    Messages : 394
    Points : 112
    Points
    112

    Par défaut

    J'appelle uint64_t realByteTransfered() il appelle bool destinationExists(), soit 2 methode avec des prototypes différent, donc même la valeur de retour doit être corrompu.

    Vu:
    https://github.com/alphaonex86/Ultra...hread.cpp#L652 appelle https://github.com/alphaonex86/Ultra...hread.cpp#L249
    PS: quand je vire le virtual de destinationExists() alors c'est ifCanStartTransfer() qui est appellé.
    Comportement espéré:
    https://github.com/alphaonex86/Ultra...hread.cpp#L652 appelle https://github.com/alphaonex86/Ultra...Async.cpp#L460

    Dit moi si je ne suis toujours pas claire
    Developpeur d'Ultracopier et Supercopier
    CatchChallenger, mmorpg old school hautes performances, insensible aux latences, support de i2p/tor, multiple gameplay.

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 929
    Points : 4 747
    Points
    4 747

    Par défaut

    Bonjour,

    S'il s'agit de 2 méthodes virtuelles, cela serait vraisemblablement dû à une corruption des objets de la liste transferThreadList. Il faut regarder en amont ce qui s'est déroulé pour trouver où le système s'est paumé.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    Consultant informatique
    Inscrit en
    octobre 2004
    Messages
    11 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : octobre 2004
    Messages : 11 109
    Points : 27 268
    Points
    27 268

    Par défaut

    Citation Envoyé par alpha_one_x86 Voir le message
    Dit moi si je ne suis toujours pas claire
    Non, en effet, tu n'es toujours pas clair...

    Dis toi que nous ne regardions pas au dessus de ton épaule lorsque tu as écrit ton code, et que l'on n'a donc aucun moyen de savoir ni tes intentions ni ce que tu as fait!

    Or, vu que tu as affaire à une hiérarchie de classes, on peut raisonnablement penser que tu manipule, quelque part, un tableau de pointeurs (que l'on ne peut qu'espérer être intelligents) sur des objets qui "passent pour être" du type de base. Mais même ca, nous n'avons aucun moyen de savoir si tel est le cas

    Et donc, la regle la plus importante, quand on pose une question sur un forum technique est de "nous aider à t'aider", en essayant de donner le plus de détails possible sur
    1. le résultat que tu recherches
    2. le code que tu as mis en oeuvre pour l'obtenir
    3. le résultat que tu obtiens

    Dans l'idéal, tu essayerais même de nous donner un code minimal compilable qui nous permettrait de reproduire le problème, en mettant en évidence le problème tel qu'il se pose; le terme "un bug" étant beaucoup trop imprécis par nature:
    • s'agit-il d'une erreur à la compilation
    • s'agit-il d'une erreur à l'édition de liens
    • ton application plante-t-elle purement et simplement si oui, n'y a-t-il pas un message quelconque qui est affiché lequel
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre régulier
    Avatar de alpha_one_x86
    Profil pro
    Développeur informatique
    Inscrit en
    décembre 2006
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : décembre 2006
    Messages : 394
    Points : 112
    Points
    112

    Par défaut

    Je recommence:
    Non le type de base ne devrai jamais être utilisé, il est surtout la pour séparer mon code.

    Je veut que quand j'appelle X() ca appelle X(), voila mon backtrace:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    1   TransferThread::destinationExists                                                                                                                         TransferThread.cpp        266  0x5cb910       
    2   ListThread::realByteTransfered                                                                                                                            ListThread.cpp            652  0x5e2ad2       
    3   ListThread::sendProgression                                                                                                                               ListThread.cpp            942  0x5e4952       
    4   QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (ListThread:: *)()>::call(void (ListThread:: *)(), ListThread *, void * *) qobjectdefs_impl.h        152  0x57a06e       
    ... <More>
    Hors cela devrai être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    1   TransferThreadAsync::realByteTransfered                                                                                                                         TransferThread.cpp        462  0x5cb910       
    2   ListThread::realByteTransfered                                                                                                                            ListThread.cpp            652  0x5e2ad2       
    3   ListThread::sendProgression                                                                                                                               ListThread.cpp            942  0x5e4952       
    4   QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (ListThread:: *)()>::call(void (ListThread:: *)(), ListThread *, void * *) qobjectdefs_impl.h        152  0x57a06e       
    ... <More>
    C'est comme si j’appelle fopen("toto") et qu'il appellais printf("toto")...
    Pas de plantage, compilation ok, pas de warning. GDB, valgrind detecte rien. Même bug avec llvm ou gcc.
    C'est comme si la v_table (https://en.wikipedia.org/wiki/Virtual_method_table) as été corrompu au runtime.
    Developpeur d'Ultracopier et Supercopier
    CatchChallenger, mmorpg old school hautes performances, insensible aux latences, support de i2p/tor, multiple gameplay.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    Consultant informatique
    Inscrit en
    octobre 2004
    Messages
    11 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : octobre 2004
    Messages : 11 109
    Points : 27 268
    Points
    27 268

    Par défaut

    ALLOO!!! Y a quelqu'un là dedans???

    J'essaye de t'expliquer que l'on n'a pas forcément le temps (ni l'envie) de commencer télécharger un projet entier juste pour analyser 3000 lignes de code dans l'espoir de trouver où se trouve le problème!

    Et c'est d'autant plus vrai que nombreuses sont tes fonctions qui sont beaucoup trop complexes (void ListThread::doNewActions_inode_manipulation() n'en est qu'un exemple, avec ces quatre niveaux d'indentation et ses... 160+ lignes de code).

    Non le type de base ne devrai jamais être utilisé, il est surtout la pour séparer mon code.
    Attention! l'héritage est la relation la plus forte qui puisse exister entre deux classes données. Cela signifie
    1. qu'il y a des règles très strictes à respecter pour pouvoir envisager d'y avoir recours
    2. que ce n'est pas la relation que l'on utilise "pour récupérer du code"
    3. que c'est sans doute la relation à laquelle on essayera -- autant que possible -- de n'avoir recours que lorsque toutes les autres solutions auront échoué

    Je veut que quand j'appelle X() ca appelle X(), voila mon backtrace:
    Oui, mais, en même temps, si x() appelle y(), il est pour le moins normal que tu vois l'appel à y() lorsque x() est exécuté

    Or, c'est bel et bien ce qui se passe

    Par contre, si j'ai bien compris, tu te plaint que ta fonction fasse appel à TransferThread::destinationExists alors que, selon toi, elle aurait du faire appel à TransferThreadAsync::realByteTransfered (on commence enfin à avancer ).

    Je vois quatre raisons possibles à ce problème:

    1- la fonction appelée n'est pas déclarée comme étant virtuelle dans la classe de base

    NOTA: depuis maintenant huit ans, nous pouvons demander au compilateur de s'assurer qu'une fonction que l'on redéfini est bel et bien virtuelle en faisant suivre le prototype de la fonction (au niveau de la classe dérivée) par le mot clé override. Si la dite fonciton n'existe pas ou qu'elle n'est pas déclarée virtuelle, le compilateur t'engueulera et s'arrêtera sur une erreur.

    Tu devrais peut-être envisager d'user et d'abuser de cette possibilité

    2- Tu transmet par valeur un élément de type TransferThread à la fonction qui espère profiter du polymorphisme en faisant appel à la fonction virtuelle, alors qu'il aurait fallu le transmettre par référence (ou par pointeur) pour que "la magie opère".

    Les informations spécifiques au type réel de l'élément transmis sont alors irrémédiablement perdue, et le compilateur fait "ce qu'il doit faire" face à l'appel de la fonction virtuelle depuis un objet qui est pour lui de type ... TransferThread.

    3- Pour une raison ou une autre, tu parcours "une collection" d'éléments de type dérivé en le considérant comme étant "du type de base" ( a priori de typeTransferThread), mais tu travaille encore une fois avec une valeur alors que tu aurais du travailler avec une référence

    Les même causes ayant les mêmes effets, tu obtiens forcément le même résultat que pour le (2)

    4 - Tu maintiens une liste par valeur d'éléments de type TransferThread, alors qu'il aurait fallu, dans le pire des cas, maintenir une liste d'éléments de type TransferThreadAsync ou, mieux encore (vu que les classes intervenant dans une hiérarchie de classes devraient être non copiable et non assignable) maintenir cette liste d'éléments sous forme de pointeurs sur des élémetns de type TransferThread (de préférence intelligents, si tu ne les fais pas entrer dans le système parent / enfants de Qt)

    Quoi qu'il en soit, quand tu es confronté à une erreur dont le symptôme principal est que le polymorphisme d'une fonction n'est pas appliqué alors qu'il aurait du l'être, c'est toujours parce que, à un moment ou à un autre (et parfois bien avant l'appel de la fonction virtuelle qui pose problème), tu n'es pas passé par une référence (ou un pointeur) en manipulant un objet de type dérivé et en le considérant comme étant un objet du type de base, et parce que -- pour une raison qu'il t'appartient de déterminer -- une copie de l'objet (considéré comme étant du type de base) aura été créée à partir de l'objet du type dérivé.

    Pour le reste, ton projet est beaucoup trop foutoir pour que j'ai envie de commencer à l'éplucher. Tu devras donc sans doute essayer de déterminer "où le bât blesse" par toi-même, à moins que tu ne nous donne d'avantage de précision sur le fonctionnement de ton projet
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre régulier
    Avatar de alpha_one_x86
    Profil pro
    Développeur informatique
    Inscrit en
    décembre 2006
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : décembre 2006
    Messages : 394
    Points : 112
    Points
    112

    Par défaut

    Salut, oui un exemple simple marche. Et si j'ai ce genre de bug, c'est justement car je refactorise et nettoie ce code... de 15ans d'accumulation...

    1) ok, pas de changement
    2) Je pense n'appeler que par pointer et avec le type hérité
    3) Idem j'ai chercher sans trouver
    4) idem

    Merci de ton coup de main.

    Voila ce qui est étrange: Si je vire tout les mots clef virtual, alors tout marche.
    Je ne comprends rien à la cause possible. Car ca contre-dit les 4 points que tu as cité.
    Developpeur d'Ultracopier et Supercopier
    CatchChallenger, mmorpg old school hautes performances, insensible aux latences, support de i2p/tor, multiple gameplay.

Discussions similaires

  1. [FLASH 8] moviecliploader et préload qui bug
    Par Twist dans le forum Flash
    Réponses: 5
    Dernier message: 23/01/2007, 16h27
  2. innerHTML qui bug sous IE
    Par krolineeee dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 13/06/2006, 16h28
  3. [Ouverture fichier] Chemin qui bug !
    Par nebule dans le forum Fichiers
    Réponses: 15
    Dernier message: 18/05/2006, 09h59
  4. [2.0] Get sur une variable d'application qui bug ??
    Par brousaille dans le forum ASP.NET
    Réponses: 8
    Dernier message: 14/03/2006, 05h08
  5. [RCP]tuto Ibm qui bug
    Par sglug dans le forum Eclipse Platform
    Réponses: 2
    Dernier message: 03/10/2005, 15h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo