Vous avez dit Memcpy() ?! [Résolu] - C - Programmation
Marsh Posté le 03-12-2008 à 10:40:33
Que fait la fonction dstr(7, 0) ?
J'ai un peu l'impression qu'il te manque le zéro terminal des chaînes (tu fais après un DStr->ptr = "String2"; et "String2" fait juste 7 caractères !
_last_l est une variable globale ? peut-être à éviter non ?
Marsh Posté le 03-12-2008 à 10:46:34
La fonction dstr(7, 0) créé un DynString de longueur 7, effectivement.
Je crois voir qu'il manque effectivement un espace mémoire pour le zéro terminal.
D'où ce foutu segfault je pense ... le copier/coller est définitivement à maudir !
Je m'en vais essayer.
Le projet que je teste fait plus de 2 millions de lignes de code, comprenez un peu le problème, j'ai du mal à tout garder en tête.
Je sais pas comment mon directeur R&D s'y prend, moi j'ai du mal
Merci
Vincent.
Marsh Posté le 03-12-2008 à 10:55:56
Me revoilà, j'ai modifié la fonction dstr(), et la voilà :
Code :
|
Du coup, elle créé un DynString de longueur 7 et alloue un espace mémoire de 8.
Et la variable "_last_l" est déclarée en "static int" dans le source de dstr().
Mais toujours est-il que j'ai encore le même problème.
Une erreur de segmentation au même endroit.
Je creuse, mais ça devient un dialogue de sourd entre moi et ma machine.
Merci pour les réponses qui suivront éventuellement
Vincent.
Marsh Posté le 03-12-2008 à 14:02:16
MindKiller67 a écrit : Me revoilà, j'ai modifié la fonction dstr(), et la voilà :
Du coup, elle créé un DynString de longueur 7 et alloue un espace mémoire de 8. Et la variable "_last_l" est déclarée en "static int" dans le source de dstr(). Mais toujours est-il que j'ai encore le même problème. Une erreur de segmentation au même endroit. Je creuse, mais ça devient un dialogue de sourd entre moi et ma machine. Merci pour les réponses qui suivront éventuellement Vincent. |
C'est clair que tu as un probleme avec une telle definition.
s->length = size ;
s->alloced = size+1 ; (ou size? Mais savoir ce que fait CheckAlloced serait aussi utile ici pour savoir ce qu'il faut mettre comme valeur dans s->alloced)
me semblerait plus juste...
Notes que tu peux garder s->length = 0 ; si tu veux mais alors, apres la ligne
DStr->ptr = "String2";
il faut faire
DStr->length = size ;
A+,
Marsh Posté le 03-12-2008 à 14:14:50
j'ai l'impression que dstrcat(DStr, s1); sert a concaténer DStr et s1, le tout dans DStr->ptr ? Du coup il faut penser à allouer (avec dstr()) suffisamment de mémoire pour accuillir le nombre de caractères égale à la somme des deux:
DynString DStr;
char *s1="String1", *s2="String2";
DStr = dstr(strlen(s1)+strlen(s2), 0);
DStr->ptr = s2;
Marsh Posté le 03-12-2008 à 14:22:19
Oui, je viens de reagir en relisant son code:
Citation : DStr->ptr = "String2"; |
c'est censé marcher??
le = ca ne vas pas faire une copie d'un buffer dans un autre.
Il va falloir d'abord correctement faire les choses. (strcpy...)
djobidjoba, tu as aussi vu le pb puisque tu as ecrit:
Citation : DStr->ptr = s2; |
mais je pense qu'il faut faire une copie, car il y a le risque de modifier effectivement s2, par effet de bord. Ce qui n'est peut être pas voulu
Citation : il faut penser à allouer (avec dstr()) suffisamment de mémoire pour accuillir le nombre de caractères égale à la somme des deux: |
A priori, je pense que c'est ce que fait checkAlloced dans son dstrcat, c'est pourquoi je demandais ca dans mon post precedent.
A+,
Marsh Posté le 03-12-2008 à 14:37:49
Je te montre le code de la fonction CheckAlloced, mais y'a rien de mystérieux.
Code :
|
En fait, elle ne fait que réallouer la mémoire et placer alloced à sa valeur juste.
dstr() ne fait qu'une allocation, sans s'occuper de la taille, mais dstrcat() lui remet les pendules à l'heure en appelant CheckAlloced().
J'ai débuggé et il se trouve que "alloced" prend la valeur du multiple de "grain" directement supérieur à "size".
Après les opérations, tout va bien. Les valeurs sont correctes.
Mais ca plante à :
Code :
|
Et non, je ne peux pas modifier le code en remplaçant mon CheckAlloced() par autre chose.
Marsh Posté le 03-12-2008 à 14:41:00
Ici le = c'est une copie de pointeur et c'est valable uniquement dans la fonction en cours.
Marsh Posté le 03-12-2008 à 14:47:11
djobidjoba a écrit : Ici le = c'est une copie de pointeur et c'est valable uniquement dans la fonction en cours. |
Ce qui rend caduc le malloc du buffer de Dstr...
Donc manifestement, c'est une copie qui est recherchée.
A+,
Marsh Posté le 03-12-2008 à 14:55:11
dstr() est utilisée dans la fonction en cours mais c'est clair qu'un bon vieux str/memcpy c'est plus sûr.
là où ca devient incorrect c'est si test_dstrcat retourne DStr, mais le compilateur envois un warning là.
Marsh Posté le 03-12-2008 à 15:00:40
MindKiller67 a écrit : Et non, je ne peux pas modifier le code en remplaçant mon CheckAlloced() par autre chose. |
Non non, c'était juste pour être sur que ca faisait bien de la reallocation (et pas un simple check). Aucune raison de modifier cette fonction.
Si tu remplaces
Citation : DynString DStr = dstr(7, 0); |
par
char* s2 = "String2":
DynString DStr = dstr(strlen(s2)+1, 0); (ou DynString DStr = dstr(strlen(s2), 0); avec ton dstr modifié)
strcpy(DStr->ptr, s2);
DStr->length = strlen(s2);
ca devrait coller, mais il serait plus propre de faire une fonction
DynString_t *make_dstr(char *s) {
int l = strlen(s);
DynString_t *ds = dstr(l+1, 0); // ou dstr(l, 0); si ton dstr fait une allocation de l+1 pour le buffer
strcpy(ds->ptr, s);
ds->length = l;
return ds;
}
et tu appelles ca dans ton code avec
DynString DStr = make_dstr("String2" );
A+,
Marsh Posté le 03-12-2008 à 15:06:17
Ok bien compris, j'vais faire une petite fonction à côté ... mais ca me plait pas trop, j'ai pas le droit dans la logique
Effectivement ça fonctionne pas non plus en mettant "DStr->length" à 7.
Pour ce qui est de test_dstrcat(), c'est une fonction de test qui ne renverra strictement rien. Elles sont appelées et fournissent des infos via le CU_ASSERT() pour afficher le résultat du test, c'est tout.
Par contre je vois pas ce que tu veux dire par "Donc manifestement, c'est une copie qui est recherchée.", m'sieur Gilou
Lors de l'écriture de tests, on doit utiliser l'API telle qu'elle est ^^
Je crois voir le bout du tunnel au loin, une lumière blanche et aveuglante !
Merci.
Vincent.
Marsh Posté le 03-12-2008 à 15:24:43
Citation : Par contre je vois pas ce que tu veux dire par "Donc manifestement, c'est une copie qui est recherchée.", m'sieur Gilou |
Quand tu fais:
DynString DStr = dstr(7, 0);
Dstr->ptr pointe sur le buffer que tu as alloué en faisant s->ptr = malloc( size+1 ) ; dans dstr
quand apres tu fais:
Dstr->ptr = "String2"
Tu perds ce que tu avais alloué, car tu écrases l'adresse de la zone allouée par celle de la chaine "String2" (qui d'ailleurs est dans une toute autre zone memoire)
-----------------------------------------------------------------------------------------------
Et incidemment, Dstr->length pointe toujours sur 0 a priori (si tu as fait, s->length = 0 dans dstr), ce qui va faire de gros problemes dans dstrcat.
Comme tu as Dstr->length = 0, et que String1 et String2 de meme taille, checkAlloced va trouver qu'il y a assez de place, ne va rien allouer, et dstrcat va essayer d'ecrire la chaine concatenée a la position s->ptr+s->length = s->ptr a la ligne memcpy( s->ptr+s->length, s1, l ) ;
Donc dstrcat est en train d'essayer d'écrire "String1" a l'emplacement ou il y a "String2", chaine constante, donc zone protégée en écriture.
kaboing...
Capice?
-----------------------------------------------------------------------------------------------
Donc plutot que d'ecraser l'adresse de la zone allouée, tu gardes ton buffer, et tu ne fais pas Dstr->ptr = "String2".
Tu remplis ton buffer en faisant une copie strcpy(Dstr->ptr, "String2" ) et tu ajuste la taille de ta chaine dynamique Dstr->length = strlen( "String2" )
A+,
Marsh Posté le 03-12-2008 à 15:25:39
Ca fonctionne, merci en tout cas pour m'avoir aidé
Par contre, si jamais vous avez une solution alternative, afin de ne pas créer de fonction annexe, je suis preneur.
Mon code passera pas la validation avec ça :
Code :
|
Doit y avoir un moyen d'initialiser ce foutu DynString autrement, j'vais y bosser perso, que mon code soit valable
En tout cas vraiment un grand merci pour l'idée de la petite fonction. Ca me permet de débugger le reste de l'application en attendant de trouver.
Marsh Posté le 03-12-2008 à 15:47:24
Bon, au vu de ces troislignes de CheckAlloced,
Citation : int ll = MAX( s->alloced+s->grain, s->length+l ) ; |
on comprends que le champ alloced fait 1 de moins que ce qui est reellement alloué
Donc ta fonction *dstr doit être comme suit:
Code :
|
avec ça, ton code initial devient:
Code :
|
Ce qui ne fais donc pas de grosse modif a ton code initial.
Un code un poil plus secure serait de faire:
Code :
|
A+,
Marsh Posté le 03-12-2008 à 16:23:21
Ben à la limite, j'peux utiliser dstrcat :-°
Aucune idée de pourquoi je n'y ai pas pensé avant.
Mon code deviendrait :
Code :
|
Ce qui ferait que :
J'initialise deux chaînes de caractère.
Je concatène une chaîne de base (s1) à mon DynString vide.
- J'obtiens donc un DynString avec la valeur de la première chaîne (s1).
Je concatène la deuxième chaîne (s2) au DynString construit ci-dessus.
- J'obtiens donc le même DynString avec DStr->ptr = "String1String2".
Fin de l'histoire ... :-)
C'est ton :
Code :
|
qui m'y a fait penser !
Merci à tous, à bientôt.
Marsh Posté le 03-12-2008 à 10:04:58
Bonjour à tous,
Voilà je suis actuellement sur un projet d'écriture de tests unitaires en C.
J'utilise la librairie classique de CUnit, libcunit.so.
Mais lorsque mon code en arrive à la phase suivante, il segfault direct.
Ca se passe à la ligne intitulée :
Apparemment, dstrcat() fait appel à la fonction memcpy() de la libcunit.
Je fourni donc la fonction dstrcat() :
et même la structure DynString() :
EDIT : Je vous fourni aussi le résumé du debug via GDB, qui sait, ça pourra peut être servir.
Si quelqu'un aurait une idée, je me bat depuis hier matin et j'ai pas l'impression d'avoir fait une erreur monumentale.
Merci d'avance
Vincent.
Message édité par MindKiller67 le 03-12-2008 à 16:24:54