Limitation d'une DLL [Résolu]

Signaler
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005
-
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005
-
Bonjour,

J'ai une question assez pointue sur les DLL. Depuis quelques temps je
m'interesse de pres aux DLL, à leurs limitations et leur
fonctionnement.

J'ai constaté que la taille maximale d'une variable, valeur de retour
d'une methode exportée par une DLL est de 6000 octets. Est ce que cela
vous semble normal ? Est ce un hasard, voir une erreur ? Quelqu'un
connaitrait il l'origine de cette limite, et si oui, en existe t il
d'autres du meme genre ?

Pour etre plus precis quant à mon probleme, j'ai une methode dans une
DLL qui retourne une chanine de caractere assez longue. Il ne semble
pas y avoir de probleme en interne de la DLL. Mais lorsque l'on
recupere cette chaine à l'exterieur de la DLL, nous avons droit à une
limitation à 6000 octets.

Si quelqu'un à des lectures TRES detaillée sur la vie et comportement des DLL, je suis preneur. D'avance merci.

Emmanuel.

16 réponses

Messages postés
298
Date d'inscription
jeudi 12 juin 2003
Statut
Membre
Dernière intervention
9 juillet 2008
1
je pense qu'il faut ajouter une ligne dans le fichier .def de ton projet.
c'est HEAPSIZE ... (la taille)
bonne chance
a+
Messages postés
2070
Date d'inscription
mardi 22 avril 2003
Statut
Membre
Dernière intervention
3 juillet 2006
8
Richter :
http://brunews.free.fr/brunews/download/JR4.zip
http://brunews.free.fr/brunews/download/JR4Sources.zip

Sinon, une chaîne de caractères c'est normalement simplement un pointeur sur le premier caractère de la chaîne.

Si la chaîne fait 6000 octets, elle doit être allouée dynamiquement (malloc, new, HeapAlloc, VirtaulAlloc...) et retournée par une fonction de la dll. Une autre fonction doit alors permettre de la libérer (en prenant comme param le pointeur).

Donc il devrait y avoir 2 fonction du genre :
char* GetString();
void FreeString(char* s);
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

Bonjour,

Merci de ta reponse, mais malheureusement la reference que tu donnes ne
contient pas la reponse à mes questions. Je l'ai déjà lue. Elle est
vraiment bien, mais pas encore assez pointue... Je suis au courant pour
l'histoire d'allocation de mémoire... :-)

Je sais aussi qu'il ne faut pas désallouer un objet alloué dans un
runtime, dans un autre runtime, et donc qu'il faut prévoir des méthode
permettant de detruire les objets créée dans une DLL et manipulé à
l'exterieur.

Non la question est un peu plus compliquée. Mon constat est qu'une
chaine correctement allouée dans une DLL, ayant une taille de plus de
8500 octets, se retrouve tronquée à 6000 octets à l'exterieur de la
DLL. (pour info elle est allouée avec un malloc, faudrait il faut un
HeapAlloc ?, je n'y connait pas grand chose en Heap).

Voila.



Emmanuel.
Messages postés
2070
Date d'inscription
mardi 22 avril 2003
Statut
Membre
Dernière intervention
3 juillet 2006
8
Si elle est tronquée c'est peut-être qu'il y a un problème d'écrasement mémoire. Il suffit pour cela qu'une instruction aille écrire un 0 à l'octet numéro 6000 de ta chaîne. Une dll peut allouer autant de mémoire que le système le permet. C'est d'ailleurs une fonction d'une dll (kernel32) qui fait les allocations sous windows (VirtualAlloc). Par ailleurs, tu peux essayer d'utiliser cette fonction.
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
salut,

si malloc ne renvoie pas d'erreur (cad le pointeur NULL), si tu as fait
un malloc(8500) alors 8500 octets ont été alloués! Comment sais tu que
seulement 6000 octets l'ont été? malloc ne renvoie pas le nombre
d'octets effectivement alloués...

De plus la DLL est mappée dans l'espace mémoire du processus qui
l'utilise, si tu fais une allocation dynamique, aucune différence entre
faire un malloc depuis le code de l'exe ou depuis le code de la DLL...

Je pense que l'erreur vient d'ailleurs. Pour tester remplace malloc par
HeapAlloc(GetProcessHeap(),0,nb_octets); (ce qui risque de ne rien
changer car malloc fait finalement appel a cette fonction), et remplace
free par HeapFree(GetProcessHeap(),0,adresse);

enfin bref, poste un bout de code, a mon avis c'est un bug qui vient d'un autre endroit..

a++
Messages postés
700
Date d'inscription
mardi 30 décembre 2003
Statut
Membre
Dernière intervention
27 janvier 2009
4
ha en plus, si le nombre d'octets de la chaine est limité a 8500, tu peux faire un truc du genre:



char* Traiterment(....) //fonction dans la DLL

{

static char retour[8500];

// tu mets ce qu'il faut dans retour



return retour;

}



si ta fonction n'est appelée que depuis un seul thread t'auras pas de problèmes.

a+
Messages postés
933
Date d'inscription
dimanche 1 avril 2001
Statut
Modérateur
Dernière intervention
9 janvier 2012
2
Suffit d'envoyer à la DLL un pointeur sur une zonne mémoire allouée (ou alors la dll allouera la mémoire) et elle retourne ce pointeur donc plus de limites.

@+
Arnotic,
Admin CS, MVP Visual C++
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

Alors merci pour ces reponses.

Mais je voudrais preciser certains détails. Il y a une grande
différence entre le fait d'allouer un objet dans une DLL ou dans l'exe
qui fait appel à la DLL. En effet, ils partagent le meme espace
mémoire. Enfin en théorie... Si la DLL et l'exe utilise des run time
différents, alors la mémoire est gérée un êu différemment. C'est pour
cela qui ne faut pas désallouer un objet alloué dans un autre run time
sous peine de corrompre le Heap concerné par la désallocation... Pour
exemple, un programme (exe) ecrit en Delphi ne peut ou plutot ne doit
detruire un objet alloué dans une DLL ecrite en C++: run time different.

De plus il n'y a pas de réelle difference me semble t il entre déclarer
un tableau static de taille fixe alloué à la compilation, et le fait
d'alloué un tableau dynamiquement. Je precise mon propos. Si
l'allocation dynamique s'est bien passée, alors l'espace est alloué est
il n'y a plus de difference entre les deux types d'allocation

Voila pour Cosmobob.





Sinon je garantie une bonne allocation de ma chaine dans la DLL. Elle
est verifiée, testée eprouvée, blindée. Donc l'allocation est bonne,
complete et correcte et fait bien plus de 8500 octets. Mais une fois
recuperée à l'exterieur de la DLL, il n'y a plus rien apres 6000
octets, et une analyse au déboggeur Visual me peremt de constater que
la memoire apres n'est pas initialisée... Ou sont passé mes 2500 octets
manquant ?



Je vais chercher du coté de HEAPSIZE dans le fiichier .def, mais Boumarsel aurais
quelques precision sur la syntaxe, et sur les parametres utilisables
dans le fichier .def. Je n'arrive pas à trouver de refernece sur
comment s'ecrit un fichier DEF, et surtout quelles sont les options
possibles.



Merci encore pour vos reponses.

Emmanuel.
Messages postés
2070
Date d'inscription
mardi 22 avril 2003
Statut
Membre
Dernière intervention
3 juillet 2006
8
Si l'allocation est bonne, initialise la chaîne entière avec des octets précis (ce que fait en mode Debug la fonction malloc).Si à un autre endroit du prog tu ne retrouve pas tes octets alors que ton prog n'est pas censé modifier cette chaîne c'est qu'il y a un buffer overflow, une autre fonction qui n'a rien a voir écrit au delà d'un autre buffer.

Je crois qu'avec visual on peut faire un break lorsqu'une variable ou un tableau est modifié (utilisation pas très évidente surtout avec des dlls).

A mon avis, ton problème ne vient pas d'une histoire d'allocation mémoire mais plus d'un écrasement mémoire (les plus durs à détecter...)
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

La mise en evidence du probleme qui n'est pas un buffer overflow ni un
ecrasement mémoire, est faite en utilisant le deboggeur Visual, en pas
à pas. Je rentre dans la DLL via le deboggeur. Je constate que ma
chaine est bien formée, et je la retourne. Et au retour de la fonction,
la chaine qui etait bonne juste avant le retour, est tronquée.... Et
non ce n'est pas un probleme de caractere de fin de chaine (0) ou
autre. La zone mémoire dépassant les 6000 octets, n'est ni initialisée
ni allouée. Je viens de me prendre suffisamment la tete avec des
histoires d'ecrasement mémoire pour commencer à les sentir, et si
besoin est j'utilise un magnifique outils de tests (INSURE++) qui
detecte a merveille ce genre de probleme.

Merci quant meme.
Messages postés
2070
Date d'inscription
mardi 22 avril 2003
Statut
Membre
Dernière intervention
3 juillet 2006
8
il reste encore l'histoire des conventions d'appel (__stdcall, __cdelc) mais j'y crois pas trop, le prog aurait du planter sans revenir dans la fonction initiale.

Pourrais-tu mettre le corps de cette fonction ? Parce que là j'ai vraiment plus d'idées...
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

Je confirme ce n'est pas une histoire de convention d'appel, ni une
histoire d'alignement, ayant aussi galerer dessus je commence à avoir
des automatismes. J'en profite pour demander si quelqu'un aurait des
explications detaillées sur les conventions d'appels, quand utilisé
stdcall quand utiliser cdecl et ... J'ai lu pas mal d'explications sur
le sujet mais je n'arrive toujours pas a voir quand on doit, quand on
peut mettre stdcall ou cdecl.

J'ai des cas, ou je dois mettre du cedecl dans la declaration de mes
pointeurs de fonctions, et d'autres ou il faut stdcall, et je n'arrive
pas à savoir pourquoi. Cela marche ainsi et pas autrement, et pour le
moment je les place en mettant de preference stdcall, et cedecl quand
cela ne marche pas... Ce n'est pas terrible comme façon de faire.



Pour le bout de code, j'ai peur qu'il ne t'apporte pas grand chose...

//DLL

// methode exportée

char* getTrialConfiguration()

{

char* trialSerialized = m_Trial.getSerialDescription();

// la chaine trialSerialized est correctement allouée et tout va bien

return trialSerialized ;

}



// EXE

typedef char* (__stdcall *getTrialDesc )();



HINSTANCE hInst = LoadLibrary("MaDLL");

getTrialDesc pGetTrialDesc;

pGetTrialDesc = (getTrialDesc )GetProcAddress(hinstDLL, "getTrialConfiguration");

char * trialSerialized = NULL;
trialSerialized =
pGetTrialDesc();

// Le retour se fait correctement mais ma chaine est tronquée...
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
27
Un bloc mémoire alloué par VirtualAlloc est indépendant de tout runtime et peut être transmis entre exe et dll sans problème.

ciao...
BruNews, MVP VC++
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

Merci pour le coup de VirtualAlloc
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
27
Note que ymca2003 te l'avait déjà dit plus haut.

ciao...
BruNews, MVP VC++
Messages postés
23
Date d'inscription
mardi 30 novembre 2004
Statut
Membre
Dernière intervention
8 février 2005

Tout à fait. Mais l'explication allant avec le VirtualAlloc n'est pas
la meme. Et dans le cas present, le probleme ne semblait pas etre un
probleme d'allocation de memoire. Mais si on me dit que ce systeme
d'allocation fonctionne malgré l'utilisation de run time different,
alors cela change la vision du probleme.



Bonne journée.