PSylvie
Messages postés16Date d'inscriptionlundi 12 juillet 2004StatutMembreDernière intervention13 août 2004
-
5 août 2004 à 12:09
Max -
13 août 2013 à 14:51
Bonjour,
Je possède une dll sous eVC++ 3.0 qui fonctionne parfaitement. Cependant, j'ai écrit une application sous eVC++ 4.0. qui a besoin de cette dll. Si je transporte la dll en eVC++ 4.0, elle plante (violation d'accès). Par contre, mon application eVC++4.0 fonctionne très bien avec la dll sous eVC++3.0!!! Quelles sont les différences entre eVC++ 3.0 et 4.0 qui font que ma dll ne fonctionne pas sur 4.0? Quelqu'un peut-il m'aider? Merci d'avance.
Sylvie
PSylvie
Messages postés16Date d'inscriptionlundi 12 juillet 2004StatutMembreDernière intervention13 août 20042 6 août 2004 à 10:08
Bonjour,
Mon problème est résolu. J'explique ici pourquoi cela ne fonctionnait pas au cas où quelqu'un rencontrerait un problème similaire.
C'est en fait une fonction « memset » qui faisait planter l'application. Il semblerait que cette fonction memset ne fonctionne pas correctement sur des adresses qui ne sont pas alignées sur 4 bytes. Cependant, le compilateur C génère ce genre d'adresses, ce qui cause le plantage de la fonction memset. Cela fonctionne très bien si le code est compilé en C++. Pour contourner ce problème, il a fallu insérer un champ supplémentaire dans la structure sur laquelle travaillait la fonction memset pour « forcer » à aligner les adresses sur 4 bytes (une autre solution consisterait à créer sa propre fonction memset).
J'espère que cette explication pourra aider d'autres personnes?
Sylvie
PSylvie
Messages postés16Date d'inscriptionlundi 12 juillet 2004StatutMembreDernière intervention13 août 20042 13 août 2004 à 11:44
Bonjour
Je poste ici une constatation faite pour voir un peu ce que vous en pensez et éventuellement dépanner quelqu'un. J'avais posté une question il y a une semaine ou deux concernant un problème de transport d'une dll de eVC++ 3.0 en eVC++ 4.0. Le problème s'avérait en fait venir d'une fonction « memset » qui était mal exécutée et qui faisait planter l'application. Le vrai coupable est enfin démasqué : le compilateur !! Preuves à l'appui?
typedef struct
{
long s32Id;
void *pvTtsData;
IVX_TTS_Sentence_Data SentenceData;
long a;
} IVX_TTS_Data;
/* Small test function */
void test()
{
IVX_TTS_Data* data;
ErrorMessage(TEXT("Creates structures"), NULL,0,0);
data=(IVX_TTS_Data*)malloc(sizeof(IVX_TTS_Data));
ErrorMessage(TEXT("adress of data->SentenceData.szLastWord"),NULL,(long)data->SentenceData.szLastWord,2);
memset(data->SentenceData.szLastWord, 0, MAX_INFO_LENGTH*sizeof (char)); //Plante ici
ErrorMessage(TEXT("It crashed ??? or not ???"), 0,0,0);
/* Never goes here:
When compiling in C, for ARMV4 -> it generates wrong ARM mnemonics!!!! */
free (data);
}
------------------------------------------------------------------------------------------------------------
Voici le bout de code assembleur généré en ce qui concerne le « memset » et la fonction « ErrorMessage » qui suit (et qui n'est jamais exécutée vu que le programme plante au memset) :
------------------------------------------------------------------------------------------------------------
; 57 : memset(data->SentenceData.szLastWord, 0, MAX_INFO_LENGTH*sizeof (char)/*data->SentenceData.szLastWord)*/);
; 58 : ErrorMessage(TEXT("It crashed ??? or not ???"), 0,0,0);
C'est ce qu'on obtient quand l'optimisation est haute (/O2) : la fonction « memset » est remplacée par une suite d'instructions « str » visant à mettre à 0 le champ « szLastWord » de la structure (ce qui est le but de la fonction « memset » !). Plantage dans ce cas?
Par contre, si l'optimisation est basse (/O1), le code assembleur correspondant est le suivant :
Là, pas d'optimisation de la fonction « memset », le compilateur décide de l'appeler telle quelle. Plus de plantage !!
Explications :
La fonction « str » a besoin, pour fonctionner correctement, d'adresses alignées sur 4 bytes. Si ce n'est pas le cas, l'adresse est arrondie inférieurement à un multiple de 4 !! (voir « Assembler Guide » de www.arm.com : http://www.arm.com/pdfs/DUI0204D_rvct_ct_ag.pdf)
Si l'optimisation est haute (/O2) et si le troisième paramètre de la fonction « memset » est un multiple de 4 (ce qui est le cas dans le programme ci-dessus : MAX_INFO_LENGTH=40), le compilateur décide d'optimiser le code en remplaçant la fonction « memset » par des instructions « str ». Par contre, si le troisième paramètre n'est pas un multiple de 4, le compilateur décide de faire directement appel à memset (comme si l'optimisation était basse /O1). C'est ce que l'on peut constater si on remplace le troisième paramètre de « memset » « MAX_INFO_LENGTH*sizeof (char) » par « (MAX_INFO_LENGTH-2)*sizeof (char) ».
Cependant, il se fait que la structure contient un « short » (« unsigned short u16Duration ») juste avant le champ utilisé dans « memset » (« char szLastWord[MAX_INFO_LENGTH] »). Dès lors, ce champ commence en une adresse non multiple de 4 (en r4 + #0xE, comme on peut le voir dans le code assembleur), l'adresse de ce champ n'est donc pas alignée sur 4 bytes. Le « paramètre » [r4, #0xE] n'est pas apprécié par l'instruction « str » qui l'arrondi inférieurement à un nombre multiple de 4. La mise à 0 faite par la première instruction « str » commence donc trop tôt (de 2 bytes, le paramètre [r4, #0xE] est remplacé par [r4, #0x10] qui ne correspond plus au début du champ à mettre à zéro) et cause le plantage de l'application.
En bref, lorsque le compilateur décide d'optimiser la fonction « memset » par des instructions « str », il ne vérifie que le fait que le troisième paramètre soit un multiple de 4 mais ne vérifie pas que le champ à mettre à 0 est aligné sur 4 bytes. Or, ce sont ces deux conditions qui sont nécessaires afin de pouvoir se servir proprement de l'instruction « str ».
Deux solutions :
1. Baisser le niveau d'optimisation du compilateur
2. Introduire dans la structure un autre « short » avant le champ szLastWord[MAX_INFO_LENGTH] pour que ce dernier soit bien aligné sur 4 bytes.
Alors là, désolé de déterrer le truc presque 10 ans après (oui, je bosse sur evc++ 4, et alors?), mais je suis sur le c*l que personne n'ai apprécié la performance de l'investigation et la précision de l'explication!
Ce genre de bug, je vous mets au défie de les trouver et de les comprendre!