IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

 C++ Discussion :

Problème création dll


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut Problème création dll
    Bonjour,

    Je suis actuellement en train de créer une dll qui gère la connexion et la communication avec un périphérique USB. Cette dll ne contient que des fonctions, pas de classe, et elle est exploitée par un programme test : une IHM C++/Qt.

    Ma "dll" est compilée avec gcc et je mets des extern "C" englobant la déclaration de mes fonctions dans le header le .cpp.

    Il se passe quelque chose d'étrange :

    Une fonction de la dll provoque un comportement étrange : Son appel depuis l'IHM semble déplacer la mémoire réservée à l'IHM. Je veux dire par la que l'IHM est composée d'une classe simple qui contient des attributs. Une fois l'appel de fonction réalisé, tous les attributs de la classe prennent une valeur aléatoire, tandis que les variables globales ou locales n'appartenant pas à la classe ne sont pas modifiées. C'est même valable pour la valeur prise par un slider et retournée par : slider.value();

    Je ne comprends pas. Evidemment cela fait planter mon appli.

    IHM:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myfunction(class_attribute)
    DLL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void myfunction(float value) {
        puts(value);
    }
    Ceci affiche un nombre "aléatoire"

    le même affichage après l'appel de fonction dans l'IHM affiche également un nombre aléatoire.

    Quelqu'un a soumis l'hypothèse selon laquelle le problème pouvait venir du caractère dynamique de la librairie qui est utilisée tel un objet dynamique. Qu'en pensez vous ? La plupart des fonctions marche et un programme simple sans IHM semble fonctionner.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void myfunction((float value) {
        puts(value);
    }
    Ne devrait pas compiler AFAIK, puisque puts prend en argument une chaine C et non un float. Je suppose donc que ce n'est pas ta vrai signature ou le cvrai code, ce qui ne nous aide pas...

    Sinon, comment est déclarée ton instance de la classe? Variable locale? Ou argument d'une fonction passé par copie? Si c'est le cas, elle est sur la pile ce qui pourrait indiquer une corruption de la pile. As-tu pensé à préciser la convention d'appel dans le header de ta DLL? Parfois on voit un mismatch de la convention d'appel utilisé enrte binaire appelant et DLL, ce qui entraîne une corruption de la pile.

    Quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    extern "C"{
    void myfunction(float value) __attribute__ ((stdcall))
    }
    EDIT: stupide faute de frappe, il faut 2 parenthèses imbriquées

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Citation Envoyé par therwald Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void myfunction(float value) {
        puts(value);
    }
    Ne devrait pas compiler AFAIK, puisque puts prend en argument une chaine C et non un float. Je suppose donc que ce n'est pas ta vrai signature ou le cvrai code, ce qui ne nous aide pas...
    Non effectivement, ce n'est pas le code réel, mea culpa.Voici un meilleur extrait du code qui plante

    IHM.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        private:
            int m_var1, m_var2, m_var3, m_var4;
    Ces variables sont initialisées à 0;

    IHM.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    cout << m_var1  << m_var2 << m_var3 << m_var4 << endl;
    myfunction(1, m_var1);
    cout << m_var1  << m_var2 << m_var3 << m_var4 << endl;
    myfunction(2, m_var2);
    myfunction(3, m_var3);
    myfunction(4, m_var4);
    Et par exemple cela m'affiche en sortie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    0000
    -15132513540010651-16106506106

    Citation Envoyé par therwald Voir le message
    Sinon, comment est déclarée ton instance de la classe? Variable locale? Ou argument d'une fonction passé par copie? Si c'est le cas, elle est sur la pile ce qui pourrait indiquer une corruption de la pile.
    Si tu parles de la classe IHM, elle est déclarée de manière non dynamique en local dans mon main.cpp



    Citation Envoyé par therwald Voir le message
    As-tu pensé à préciser la convention d'appel dans le header de ta DLL? Parfois on voit un mismatch de la convention d'appel utilisé enrte binaire appelant et DLL, ce qui entraîne une corruption de la pile.

    Quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    extern "C"{
    void myfunction(float value) __attribute__ (stdcall)
    }
    J'essaye de jeter un oeil, mais je suis sur Linux, et cela ne semble pas compiler.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par 0_Azerty_0 Voir le message
    J'essaye de jeter un oeil, mais je suis sur Linux, et cela ne semble pas compiler.
    En bon boulet j'avais oulié une paire e parenthèses (j'ai EDIT le mesasge précédent pour essayer de ne pas induire en erreur)

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Mais à quoi cela sert exactement ? Je suis pas à l'aise avec l'idée de pas comprendre ce que je fais !
    Par ailleurs, le extern C doit entourer uniquement les prototypes de fonction ou leur définition également ?

    Sinon, je viens de faire un test qui vient d'exclure le problème de linkage dll : J'ai inclus une copie des fichiers de la dll à mon projet pour voir ce que ca allait donner : Résultat, même erreur ! Il ne s'agit donc plus d'une histoire de dll, mais bien un problème de mémoire désormais !

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    OK, donc si en compilant monolithique le problème subsiste, c'est que ce n'est pas un soucis de DLL boundary, effectivement.
    Pour ce qui est de l'attribut stdcall (ou cdecl), l'explication est la suivante:
    au niveau binaire, l'appelant et l'appelé doivent s'accorder pour la transmission des paramètres et la gestion de la pile. C'est ce qu'on appelle la convention d'appel. Elle est habituellement sous entendu, mais les valeurs par défaut peuvent diverger dans le cas de deux binaires compilés séparément (cas typique exécutable + DLL) et dans ce cas on peut corrompre la pile ou des variables qui sont prises les unes pour les autres...
    Les attributs de convention d'appel permettent de spécifier la convention d'appel sur la fonction pour être sûr que c'est cohérent entre appelant et appelé si la fonction exposée à travers une frontière de DLL.

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Par contre il nous faudrait le code appelant ET appelé pour comprendre la corruption de mémoire...
    Tu as tenté un clean build pour écarter un problème de fichier binaire obsolète linké?

  8. #8
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Ok, je pense avoir compris, merci beaucoup !

    Fonction de la dll (ou pas) , code appelé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    void myfunction(int fingerId, int power)
    {
    	if (FILE_DESCRIPTOR < 0)
    	{
    		printf ("Error: serial output non connected when changing finger status :: dll_gloves");
    		return;
    	}
     
            //printf("DLLPower: %d  \n", power);
            if(power < 0 || power > 9)
    	{
                    power =0;
    		printf("Warning: vibration power has to be in between 0 and 9 :: dll_gloves \n");
    	}
     
    	if(fingerId != THUMB_ID && fingerId != INDEX_ID && fingerId != MIDDLE_FINGER_ID && fingerId != HAND_ID)
    	{
    		fingerId =THUMB_ID; 
    		printf("Warning: fingerId specified out of bounds :: dll_gloves");
    	}
     
    	char a[1];
    	sprintf(a,"%d",fingerId);
      	write(FILE_DESCRIPTOR, &a , 1);
    	write(FILE_DESCRIPTOR, "1" , 1);
        sprintf(a,"%d",power);
        write(FILE_DESCRIPTOR, &a , 1);
    }
    Code appelant dnas l'IHM
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
     
    cout << "Should Vibrate in Standard mode : " 
    << m_powerThumb  << m_powerIndex << m_powerMiddle << m_powerHand  << endl;
     
                if(m_powerThumb > 0 && m_powerThumb <= 90)
                    myfunction(THUMB_ID, m_powerThumb);
     
    cout << m_powerThumb  << m_powerIndex << m_powerMiddle << m_powerHand  << endl;
     
                if(m_powerIndex > 0 && m_powerIndex <= 90)
                    myfunction(INDEX_ID, m_powerIndex);
     
                if(m_powerMiddle > 0 && m_powerMiddle <= 90)
                    myfunction(MIDDLE_FINGER_ID, m_powerMiddle););
     
                if(m_powerHand > 0 && m_powerHand <= 90)
                    myfunction(HAND_ID, m_powerHand);
                else
                    stopVibrateFinger(HAND_ID);
    Voilà, et donc la sortie du cout du grand n'importe quoi une fois myfunction appelée... Tout le code qui suit ne réaslise donc pas l'action attendue

  9. #9
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Alors là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char a[1];
    sprintf(a,"%d",fingerId);
    Tu commences à labourer la pile. Penser à réserver un byte pour le \0 terminal de la string!
    PS: étant en C++, pourquoi ne pas utiliser les fonctions d'écriture C++ qui t'éviterons ces migraines de gestion de tampon?

    Sinon pour plus de diagnostic, puisque tu es sous linux, essaies valgrind pour qu'il te fasse un diagnostic mémoire. Il te diras où sont tes écritures illégitimes.
    (par ex: dans ton code, là, tu as un débordement de buffer...pour peu que le pointeur de ta struct soit juste derrière dans ta pile...)

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Je dois t'avouer ne pas m'y connaître non plus pour ce qui est de la pile. J'ai remplacé le sprintf() par un sstream+str+char*, ca fonctionne, et je dois avouer être franchement sur le cul ! je vois pas en quoi il y a un débordement de buffer, parce que je déclare un a[1] ? jusqu'ici je m'en préoccupais pas puisque j'écris ensuite uniquement le contenu de la première case du tableau à l'adresse &a !

    Tu penses qu'en déclarer un a[1], je fais un buffer trop cours et écrase ainsi (peut-etre) le pointer de l'objet appelant ? Je suis curieux de savoir !

    En tout cas, mon problème est réglé, merci à toi, et il était accessoirement couplé avec un problème dans l'écriture du port série : le problème ne survenait uniquement que lorsque l'on faisait plusieurs appels successifs de myfunction au sein de la fonction appelante. Un usleep(500), à la fin de myfunction permet de ne pas écrire "trop vite"... Je ne pensais pas qu'il fallait le contrôler manuellement !

  11. #11
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Pour t'expliquer les choses clairement: un chaîne de caractère C à base de char* prend toujours un octet de plus que sa longeur, car la fin de la chaîne est marquée par un char à 0, c'est la notion de "null-terminated character string"
    Ex:
    La chaîne "1" est représentée comme suit dans la mémoire:
    Note bien: il s'agit de la valeur 0, qu'on représente par '\0', le caractère null, et non du caractère '0', qui lui est représenté par la valeur hexa x030 (48 en décimal).
    Donc avec ton tableau char[1], tu écris le "1" (en fait un char de valeur numérique hexa 031, siot 49 en décimal) dans ton tableau, puis le \0 qui marque la fin de la chaîne...juste après le tableau. Or juste après le tableau, dans la pile, il y a une autre variable. Par exemple, l'adresse de ta structure, ou la valeur d'un de tes paramètres d'appel...en fait, n'importe quoi, ce qui peut avoir à peu près n'importe quel effet (ce qu'on appelle un comportement indéfini) y compris corrompre les données, corrompre l'adresse de retour stockée sur la pile, jusqu'à planter le programme complètement.

  12. #12
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Ok, j'ai saisi. Ces histoires de caractère nul sont effectivement très loin derrière moi, un peu gommées de ma mémoire par l'aisance de la manipulation des strings. Par ailleurs, cela me fait comprendre un autre problème que j'ai eu il y a quelques temps. Je ne suis pas prêt de refaire cette erreur, merci en tout cas !
    Mais je me demande toute de même : Comment aurais-je du faire si j'avais souhaité conserver ma syntaxe. Juste déclarer un tableau avec une taille à 2 ?

    Allez, merci d'avance et bon week-end à toi,

    Az

  13. #13
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par 0_Azerty_0 Voir le message
    Ces histoires de caractère nul sont effectivement très loin derrière moi, un peu gommées de ma mémoire par l'aisance de la manipulation des strings. Par ailleurs, cela me fait comprendre un autre problème que j'ai eu il y a quelques temps. Je ne suis pas prêt de refaire cette erreur, merci en tout cas !
    Le diable est dans les détails
    Citation Envoyé par 0_Azerty_0 Voir le message
    Mais je me demande toute de même : Comment aurais-je du faire si j'avais souhaité conserver ma syntaxe. Juste déclarer un tableau avec une taille à 2 ?
    Exactement. A condition cependant (ce qui n'est ps toujours évident!) de pouvoir GARANTIR que la chaîne fera toujours au plus un caractère. Les outils C++ de std gèrent ce problème pour toi.
    Citation Envoyé par 0_Azerty_0 Voir le message
    Allez, merci d'avance et bon week-end à toi,

    Az
    De rien, bon week-end

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. CEGUI, Problème création .dll
    Par Erwan28250 dans le forum Ogre
    Réponses: 7
    Dernier message: 17/03/2013, 22h54
  2. Problème création DLL
    Par sniperpro dans le forum Langage
    Réponses: 10
    Dernier message: 05/10/2011, 10h11
  3. Problème Création DLL
    Par Fabien25C dans le forum Débuter
    Réponses: 1
    Dernier message: 25/11/2009, 13h57
  4. Problème création de DLL avec CString
    Par loupdeau dans le forum MFC
    Réponses: 3
    Dernier message: 21/07/2005, 20h55
  5. Problème création de DLL
    Par monsieur.voie.lactee dans le forum C++Builder
    Réponses: 4
    Dernier message: 12/08/2003, 16h56

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