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++Builder Discussion :

Codeguard erreur sur destructeur


Sujet :

C++Builder

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut Codeguard erreur sur destructeur
    Bonjour,

    je passe codeguard sur mon appli et j'ai une erreur que j'ai du mal à comprendre.
    Mon appli est constituée d'une dll et d'un exe.
    Ma dll exporte la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vector<TEventData> __stdcall mLgetFaults()
    TEventData est une classe à moi.
    La partie exe récupère le vector, tout se passe bien à l’exécution, mais si je compile avec codeguard, il me signale une erreur sur le destructeur de TEventData (qui ne fait rien vu que cette classe ne contient que de types simples) :
    Bad parameter in process: MonAppli.exe(6480) - c:\program files\embarcadero\rad studio\8.0\include\dinkumware\xmemory#129
    A bad object (0x34F79E0) has been passed to the function.
    0x006909BC Call to delete(0x03507A80)
    ...................
    0x0040B38B - src\GenericData\EventData.h#45
    .............................
    à cette ligne j'ai le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	~TEventData()
    	{
    	};
    Il passe donc 2 fois dans le destructeur ce qui me parait normal en fait (une fois pour la création des TEventData dans l'exe, une fois pour la création dans la dll), mais ça ne doit pas être le cas puisque codeguard me sort une erreur...
    J'avoue que je ne comprends pas trop...

    merci d'avance pour vos suggestions d'explication
    Pascale38

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    En C++Builder 2007, mon CodeGuard me fait souvent des VA à la fermeture du projet, je crois que c'est au moment du déchargement des Packages

    Cela a été amélioré en XE2

    Sinon attention, ne partage pas d'objet entre EXE et DLL, évite de créer d'un côté et libérer de l'autre côté !

    Tu n'échange tout de même pas un vector directement ?
    Ta DLL ne pourra être utilisé qu'avec uniquement la version de ton compilateur (un vector de C++Builder6 n'aura peut-être pas la même gueule mémoire que celui de C++BuilderXE2, et je ne parle même pas des autres compilateurs C++)

    En plus, ça ne fait pas des copies dans tous les sens ça ?
    Tu devrais plutôt faire une fonction respectant les conventions WinAPI

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BOOL __stdcall mLgetFaults(TEventData* Buf, int& BufCount);
    Buf est alloué du côté appelant, il indique le nombre d'élement possible par BufCount (en nombre d'item) ou un BufSize en octet

    cela renvoi un code d'erreur pour signaler un Buf trop petit
    Typiquement, si tu fournis Buf NULL, la fonction calcule BufCount, permettant d'allouer la mémoire !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    ce point est documenté sur MSN
    voici le lien
    http://support.microsoft.com/kb/172396/fr
    cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Salut ShaiLeTroll,

    bon j'avais pas envie de m'embêter avec des pointeurs, je sais ça fait des copies, mais bon mon vector fait 24 max donc c'est pas énorme non plus.
    Mais bon merci pour l'info, je ne savais pas que c'était incompatible entre version de compilo !!
    Sinon j'utilise XE, alors comment savoir si c'est un problème codeguard ou non ?

    Utiliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BOOL __stdcall mLgetFaults(TEventData* Buf, int& BufCount);
    j'avoue que je trouve ça super lourd !! Allouer un Buf sans savoir sa taille avec une valeur au hasard... beurk
    Bon ceci dit j'ai testé, j'alloue mon buf à 24 dans l'appelant (vu que là j'ai la chance de savoir que c'est le max), je fais le delete dans l'appelant et j'obtiens exactement la même erreur codeguard... sur le delete et sur le destructeur de TEventData...

    Donc DjmSoftware, merci pour ton lien, mais il semblerait qu'il n'y ait aucun rapport avec le fait que j'utilise un conteneur de la STL.

    Pascale38

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par Pascale38 Voir le message
    j'avoue que je trouve ça super lourd !! Allouer un Buf sans savoir sa taille avec une valeur au hasard... beurk
    C'est pas faux, d'où DEUX Appels comme je l'avais expliqué dans ma réponse !
    Un Appel mLgetFaults(NULL, var);il rempli var avec ce qu'il faut allouer puis mLgetFaults(buf, var);Typique des API Windows !

    Tu peux aussi faire une liste chainée avec une fonction mLgetFaultsFirst(Buf) et mLgetFaultsNext(CurBuf, NextBuf)Fonctionnement du TreeView je crois !

    Je préfère utiliser des interfaces, ainsi, la mémoire est alloué côté DLL, tu peux avoir une propriétés Count\Items, facile à utiliser, puis une méthode pour nettoyer !
    Ainsi ma DLL n'a que deux trois Exports, dont l'un est une Factory, ensuite tout le reste c'est POO à fond !

    J'utilise aussi bien des Interface C++ (class abstraitre pure) que des DelphiInterface (TInterfacedObject, GUID et Supports ...)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Not possible pour 2 appels :
    En fait le "tableau" est construit dynamiquement à chaque appel, entre 2 appels il peut très bien contenir +ou- d'éléments...

    Les autres solutions, surement très bien, toujours un peu lourdes à mon goût...
    Tout ça pour échanger un tableau...

    Ceci dit mon problème de base avec codeguard reste le même :
    c'est donc codeguard qui bug ???

    merci en tout cas pour toutes tes pistes !!!
    Pascale38

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ce n'est pas vraiment CodeGuard qui bug mais qui ne comprend pas que l'on libère un objet alloué dans l'espace mémoire d'un processus A dans un module B
    Cela vient plutot de Windows et la gestion mémoire entre EXE et DLL

    C'est pour cela qu'il existait ShareMem en Delphi
    La RTL dynamique doit être aussi un aspect de cela !

    Tant que ta DLL reste une utilisation interne et non utilisable par des logiciels tiers, tu peux te permettre ta méthode

    Je te conseille de suivre la méthode de l'article de DjmSoftware !
    Un petit pointeur ça ne fait pas de mal !

    ton code actuel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<TEventData> __stdcall mLgetFaults();
    remplace le par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    typedef vector<TEventData> TEventDataVector;
    typedef TEventDataVector* PEventDataVector;
     
    PEventDataVector __stdcall mLgetFaults();
    void__stdcall mLFreeFaults(PEventDataVector Vector);
    Ainsi, tu échanges un pointeur créé par la DLL
    Il faudra juste libéré manuellement !
    CodeGuard sera content de voir que Allocation et Libération sont effectué du même côté !

    Je ne fais du C++ que depuis un an, en Delphi les habitudes ne sont pas les mêmes mais pour ton cas un code façon RAII serait idéal

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct TEventDataReader
    {
      PEventDataVector Items;
     
      TEventDataReader()
      {
         Items = mLgetFaults();
      }
     
      ~TEventDataReader()
      {
        mLFreeFaults(Items);
      }
    }
    Dans ton juste en déclarant un TEventDataReader cela appèle la DLL, et en le libére implicitement


    Tu peux aussi différé la lecture, si tu ne veux pas que dès que l'instanciation se produit cela appelle la DLL, par exemple si tu veux en faire un membre de classe

    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
    struct TEventDataReader
    {
      PEventDataVector Items;
     
      TEventDataReader() : Items(NULL) {};
     
      int ReadItems();
      {
         Items = mLgetFaults();
         return Items->size(): 
      }
     
      ~TEventDataReader()
      {
        if (Items)
          mLFreeFaults(Items);
      }
    }
    le code d'appel étant très simple

    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
    void MaFonction()
    {
      ...
     
      TEventDataReader Reader; 
      if (Reader.ReadItems() > 0)
      {
        for (TEventDataVector::iterator it = Reader.Items->begin(); it != Reader.Items->end(); ++it)
        {
          *it ... 
        }
      }
     
      // libération automatique à la fin du bloc
    }
    le typedef simplifie l'utilisation du type vector, cela donne un code plus rigoureux !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Ok je vais essayer ça, si ça peut rendre codeguard content
    Par contre un petit truc que je ne comprends pas quand même :
    CodeGuard sera content de voir que Allocation et Libération sont effectué du même côté !
    Dans la modif que j'ai faite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    BOOL __stdcall mLgetFaults(TEventData* Buf, int& BufCount);
    c'est bien l'appelant (mon exe) qui alloue et désalloue le Buf !! Donc allocation et libération sont bien fait du même côté !!
    Donc il ne devrait pas râler ???

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Normalement, il ne devrait pas râler effectivement !
    Que contient TEventData ? Des AnsiString ? des TDynArray ? d'autres vecteur ?
    Comment affecte tu le contenu de *Buf ? Affectation d'une variable locale ? Copie Mémoire ?

    Si tu retires le destructeur, il râle quand même car un destructeur vide n'a pas d'utilité !

    Tient j'avais aussi fait délirer CodeGuard : Thread et DLL : problème de #define, il semblait perturbé si je chargeais une DLL juste après en avoir déchargé une autre !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Bien vu, TEvenData contient un map !!
    Sinon il contient des String.
    Et le contenu de *Buf et affecter par variable locale.

    Par contre il ne râle plus avec ce type d'appel (avec allocation et désallocation dans la dll bien sur) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TEventData* mLgetFaults(int& bufferCount)

    sauf si dans mon exe je recopie mes TEventData (dans un vector bien sûr...)

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Cela peut être lié au compteur de référence des chaines
    En fait l'affectation d'un String (RTL), augmente un compteur de référence, la libération, le décrémente, il est possible que le compteur tombe a zéro du mauvais côté d'où l'erreur !

    Pour les vecteurs, je ne maîtrise pas du tout leur fonctionnemment mémoire

    Dans mes habitudes, TEventData ne contiendrait que des types API comme char*, char[] ou BSTR mais pas de type objet, cela évite ce genre de soucis, et cela rend la DLL compatible avec plus de langage
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    oui en pratique il y aura une "surcouche" avec des types simples car ma dll devra être utilisée par une autre appli en .NET
    Mais je ne pensais pas me servir de cette surcouche pour mon appli puisque elle est aussi en C++ avec le même compilo, mais peut être que je le ferai après tout vu que ça ne semble pas si simple d'échanger proprement tous types d'objets...

    Encore une fois un grand merci à toi pour ton temps et tes précieux conseils

Discussions similaires

  1. Erreur sur une fonction avec des paramètres
    Par Elois dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 05/05/2004, 21h00
  2. [VBS] Erreur sur "AddWindowsPrinterConnection"
    Par Admin dans le forum VBScript
    Réponses: 5
    Dernier message: 27/03/2004, 16h15
  3. Erreur sur serveur lié
    Par k-lendos dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 18/03/2004, 15h21
  4. []Erreur sur second emploi collection binding
    Par jacma dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 08/03/2004, 18h02
  5. Erreur sur le TNSListener après installation de 9iAS
    Par Patmane dans le forum Installation
    Réponses: 4
    Dernier message: 04/02/2004, 11h16

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