2009-06-09 8 views
3

Je dois charger des modules en tant que DLL dynamiquement au moment de l'exécution car ils ne sont pas connus à l'avance, juste qu'ils se conforment à une interface de classe. Ce que j'ai remarqué c'est qu'après avoir attrapé une exception lancée par la DLL (dans le programme principal du thread principal), les bons destructeurs sont appelés et les modules détruits et dll déchargés, mais alors comme} à la fin du bloc catch est atteint par le débogueur Visual Studio C++ lors de l'étape ligne par ligne, j'obtiens une autre exception qui bloque le programme avecViolation d'accès après avoir intercepté l'exception dll

Exception de première chance à 0x68ad2377 (msvcr90d.dll) dans xxxxx.exe: 0xC0000005: Emplacement de lecture de violation d'accès 0x02958f14 .

Si j'ENABLE casser des exceptions, brisant cette deuxième exception montre l'emplacement que

msvcr90d.dll! __ DestructExceptionObject (EHExceptionRecord * pExcept = 0x0017ee4c, unsigned char fThrowNotAllowed = 0) Ligne 1803 + 0xf octets

mais il semble que la pile de cadres soit corrompue. Je ne peux pas comprendre pourquoi cette exception est levée.

Une version simplifiée de ma structure de code est le suivant:

Une structure très simplifiée du programme:

//shared header: 
class Module 
{ 
public: 
    virtual void Foo(void) = 0; 
}; 


//dll: 
class SomeSpecificModule : public Module 
{ 
public: 
    virtual void Foo(void); 
}; 

void SomeSpecificModule::Foo(void) 
{ 
    throw 1; 
} 

extern "C" __declspec(dllexport) Module* GetModule() 
{ 
    return new SomeSpecificModule; 
} 


//program: 
typedef ptrGetModule* (*GetModule)(); 

int main(void) 
{ 
    HANDLE hMod = LoadLibrary("SomeSpecificModule.dll"); 
    ptrGetModule GetModule = (ptrGetModule)GetProcAddress(hMod, "GetModule"); 
    try 
    { 
     Module *d = GetModule(); 
     d->Foo(); 
    } 
    catch (...) 
    { 
     cout << '!' << endl; 
    } 
    return 0; 
} 
+0

Veuillez poster toute la trace de la pile –

Répondre

1

Êtes-vous cathing l'exception en valeur dans votre code réel? Dans ce cas, il peut y avoir une exception dans le destructeur de l'objet d'exception copié à la fin du bloc catch.

1

Je ne vois pas dans ce code où la DLL est déchargée (comme vous le dites). Pouvez-vous s'il vous plaît poster le code pertinent? Le déchargement de la DLL peut être crucial, car votre DLL contient le code nécessaire pour la destruction des objets, le déroulement de la pile, etc. et il n'est pas clair à partir de ce que vous avez posté à quel point la DLL est déchargée.

0

Vérifiez les paramètres de poject, si votre application est multithread alors vous devez créer un lien vers DLL multithread

4

La chose à retenir est que chaque copie de la bibliothèque d'exécution C a ses propres états. Si SomeSpecificModule.dll lie statiquement à la bibliothèque d'exécution C, ce type de problème peut se produire. Si c'est le cas, essayez de lier avec la version DLL de la bibliothèque d'exécution C. Vous devez également vous assurer que SomeSpecificModule.dll est compilé et lié exactement de la même manière que votre module principal. Vous avez mentionné DLL en cours de déchargement et les destructeurs corrects ont été appelés, il semblait que votre vrai programme a beaucoup plus de choses que l'échantillon que vous avez posté. Si vous avez déchargé SomeSpecificModule.dll dans votre bloc try, vous avez déchargé l'enregistrement d'exception pour SomeSpecificModule :: Foo(), et je suppose que c'est ainsi que vous avez obtenu le crash à m svcr90d.dll!__DestructExceptionObject(EHExceptionRecord * ...

les frontières demandent des ennuis. Si vous lancez un objet non POD, vous risquez de rencontrer des problèmes avec la mémoire allouée par différentes bibliothèques d'exécution C dans des tas différents, des paramètres de compilation différents, une version STL ... vous obtenez le point.

Modifiez votre code afin de ne pas dépasser les limites de la DLL. Un jour, un membre de votre équipe modifie le paramètre du compilateur ou un en-tête #define modifié et votre programme se bloque. Vous allez avoir du mal à retrouver la cause.

De toute façon, sans voir le vrai code, j'essaie juste de deviner ce qui pourrait mal se passer. J'espère que cela aide.

0

Cela pourrait être un coup de feu dans l'obscurité, mais la peine de vérifier.

Votre application semble être compilée dans DEBUG puisque l'erreur apparaît dans msvcr90d.dll. Les DLL que vous utilisez sont elles aussi compilées dans DEBUG? Créer de la mémoire avec msvcr90.dll et libérer avec msvcr90d.dll ou vice versa est un problème courant lors de l'utilisation de DLL.

Je pense que votre pointeur de fonction typedef ressemble un peu méfiant. Je l'écris comme ceci:

typedef Module* (*moduleFnType)(); 

int main(void) 
{ 
    HANDLE hMod = LoadLibrary("SomeSpecificModule.dll"); 
    moduleFnType GetModule = (moduleFnType)GetProcAddress(hMod, "GetModule"); 
    try 
    { 
     Module *d = GetModule(); 
     d->Foo(); 
    } 
    catch (...) 
    { 
     cout << '!' << endl; 
    } 
    return 0; 
} 

Votre typedef ne dit rien sur le type de retour de la fonction GetModule.

0

Canopus: quand je jette un entier comme l'exception, la même chose se produit.

TK___: Je suis lié à dll multithreaded dans tous les projets. Assaf et Shing Yip: Les dll sont en effet déchargés par FreeLibrary() dans le destructeur d'un wrapper pour eux, car les objets wrapper que je pousse dans un vecteur de tr1 :: shared_ptr (comme l'encapsuleur lui-même est non recopiable en tant que détenteur de ressource et ne peut donc pas être mis dans un vecteur STL) existant uniquement dans la portée try {}. Cela semblait être la bonne chose à faire, donc je peux m'assurer que le nettoyage inclut le déchargement de DLL quand il y a une situation d'erreur, et j'ai tendance à préférer la conception de style RAII. Si c'est la source du problème, alors je me demande quel type de conception à utiliser qui fonctionnerait correctement et semblerait toujours bon du point de vue de l'ingénierie logicielle. Ce qui me fait craindre que ce ne soit pas le problème, cependant, c'est que lorsque je passe par les appels de destructeur qui se produisent lorsque l'exception est levée, FreeLibrary() s'exécute sans erreur, et je peux continuer à avancer jusqu'à la fermeture } de la capture {}.

Magnus Skog: En mode de libération, je reçois également un plantage plutôt que d'attraper l'exception puis de continuer l'exécution normalement. La mémoire dynamique est gérée avec 1) opérateur nouveau dans quelques cas, 2) tr1 :: shared_ptr, et 3) _mm_malloc/_mm_free où j'ai besoin d'alignement.

+0

Juste pour info. La méthode préférée pour répondre aux réponses est d'ajouter un commentaire à la réponse (ce que vous ne pouvez pas faire car votre représentant n'est pas assez haut) ou de modifier la question originale. Vous devriez vraiment utiliser les informations supplémentaires que vous avez ici pour développer la question originale. Cela aidera les futurs demandeurs de questions à trouver cette question s'ils ont des symptômes similaires. De plus, il fait juste un meilleur "récit" du problème et de la solution. –

+0

@Prune. Voir ma réponse éditée. – ralphtheninja

3

Une grande partie du code de déroulement de pile qui doit être appelé lorsque votre DLL déclenche une exception se trouve dans la DLL. Si vous déchargez la DLL, comment appeler ce code?

Ne pas jeter des exceptions à travers les frontières du module liées dynamiquement.

Questions connexes