Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[GCC/Valgrind] Invalid read of size 4 sur strlen()

4 réponses
Avatar
JKB
Bonjour à tous,

Je viens de tomber sur un truc amusant avec valgrind (j'ai
l'impression que le truc a été mis à jour sur ma debianerie, mais
sans certitude). N'ayant pas réussi à écrire un exemple minimal, je
colle ici la fonction traitresse qui est une quick and dirty
function destinée à convertir au vol l'encodage d'une sortie. Toutes
les chaînes de caractères sont des chaînes en convention C, donc
avec un nul à la fin.

unsigned char *
reencodage(struct_processus *s_etat_processus,
unsigned char *chaine_entree,
unsigned char *codage_entree,
unsigned char *codage_sortie)
{
# define d_LONGUEUR 1024

iconv_t transcodage;

size_t ios;
size_t longueur_entree;
size_t longueur_sortie;

unsigned char *buffer_entree;
unsigned char *buffer_sortie;
unsigned char *chaine_sortie;
unsigned char *pointeur;
unsigned char *tampon;

if ((transcodage = iconv_open(codage_sortie, codage_entree)) ==
(iconv_t) -1)
{
return(NULL);
}

buffer_entree = chaine_entree;
longueur_entree = strlen(chaine_entree);

if ((chaine_sortie = malloc(sizeof(unsigned char))) == NULL)
{
return(NULL);
}

chaine_sortie[0] = d_code_fin_chaine;

if ((buffer_sortie = malloc((d_LONGUEUR + 1) * sizeof(char))) == NULL)
{
return(NULL);
}

do
{
longueur_sortie = d_LONGUEUR;
pointeur = buffer_sortie;

if ((ios = iconv(transcodage, (char **) &buffer_entree,
&longueur_entree, (char **) &pointeur, &longueur_sortie))
== (size_t) -1)
{
// On autorise les erreurs EINVAL et EILSEQ
if (errno == EILSEQ)
{
free(buffer_sortie);
free(chaine_sortie);

return(NULL);
}
}

tampon = chaine_sortie;
(*pointeur) = d_code_fin_chaine;

printf("> %d\n", strlen(tampon)); // râlage de valgrind ici.

if ((chaine_sortie = malloc((strlen(tampon) + strlen(buffer_sortie) + 1)
* sizeof(unsigned char))) == NULL)
{
return(NULL);
}

sprintf(chaine_sortie, "%s%s", tampon, buffer_sortie);
free(tampon);
} while((*buffer_entree) != d_code_fin_chaine);

free(buffer_sortie);
iconv_close(transcodage);

return(chaine_sortie);
}

Valgrind me renvoie sur le printf() (et sur la ligne suivante qui
utilise strlen(tampon)) l'erreur suivante :

==3692== Invalid read of size 4
==3692== at 0x65380C: librpl_reencodage.constprop.1
(transliteration-conv.c:139)
==3692== by 0x654435: librpl_transliterated_fprintf
(transliteration-conv.c:62)
==3692== by 0x64D3ED: librpl_rplinit (rpl-conv.c:1642)
==3692== by 0x5213CC: main (init-conv.c:29)
==3692== Address 0x9322150 is 0 bytes inside a block of size 1 alloc'd
==3692== at 0x4C2779D: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3692== by 0x653776: librpl_reencodage.constprop.1
(transliteration-conv.c:100)
==3692== by 0x654435: librpl_transliterated_fprintf
(transliteration-conv.c:62)
==3692== by 0x64D3ED: librpl_rplinit (rpl-conv.c:1642)
==3692== by 0x5213CC: main (init-conv.c:29)

Et j'ai une erreur par passage sur ce strlen(tampon).

J'ai beau prendre le problème dans tous les sens, je ne vois pas
comment ce pointeur peut-être invalide. Je précise que ce bout de
code a plusieurs années et semble fonctionner sans problème. J'ai
naturellement vérifié que le pointeur est correct à chaque passage.
Alors, bug de valgrind et BR à l'équipe de développement, ou faut-il
que je reprenne quelques jours de vacances ?

Cordialement,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr

4 réponses

Avatar
espie
In article ,
JKB wrote:
unsigned char *
reencodage(struct_processus *s_etat_processus,
unsigned char *chaine_entree,
unsigned char *codage_entree,
unsigned char *codage_sortie)
{


pourquoi des unsigned char * alors que visiblement, ce sont des char * ???
# define d_LONGUEUR 1024

iconv_t transcodage;

size_t ios;
size_t longueur_entree;
size_t longueur_sortie;

unsigned char *buffer_entree;
unsigned char *buffer_sortie;
unsigned char *chaine_sortie;
unsigned char *pointeur;
unsigned char *tampon;

if ((transcodage = iconv_open(codage_sortie, codage_entree)) = > (iconv_t) -1)
{
return(NULL);
}

buffer_entree = chaine_entree;
longueur_entree = strlen(chaine_entree);

if ((chaine_sortie = malloc(sizeof(unsigned char))) == NULL)
{
return(NULL);
}


Par definition sizeof(char) == 1
chaine_sortie[0] = d_code_fin_chaine;

if ((buffer_sortie = malloc((d_LONGUEUR + 1) * sizeof(char))) == NULL)
{
return(NULL);
}


Si tu insistes pour faire du unsigned char *, pourquoi un sizeof(char) ici ?

printf("> %dn", strlen(tampon)); // râlage de valgrind ici.



Ben deja, strlen renvoie un sizeof, donc une valeur pas signee, et pas forcement
un int de surcroit.

Je suis pas trop sur que valgrind rale pour les bonnes raisons, mais cette
ligne est passablement fausse. En C pre99, on ecrit:

printf("> %lun", (unsigned long)strlen(tampon));

et en C99:
printf("> %zun", strlen(tampon));
...
Avatar
JKB
Le Mon, 29 Aug 2011 10:57:19 +0000 (UTC),
Marc Espie écrivait :
In article ,
JKB wrote:
unsigned char *
reencodage(struct_processus *s_etat_processus,
unsigned char *chaine_entree,
unsigned char *codage_entree,
unsigned char *codage_sortie)
{


pourquoi des unsigned char * alors que visiblement, ce sont des char * ???



Parce qu'il y a une bibliothèque à la noix qui est utilisée dans un
autre bout du code qui attend des 'unsigned char *'. J'ai donc
décidé que les char étaient tous unsigned pour éviter d'avoir des
problèmes de comparaisons de caractères.

# define d_LONGUEUR 1024

iconv_t transcodage;

size_t ios;
size_t longueur_entree;
size_t longueur_sortie;

unsigned char *buffer_entree;
unsigned char *buffer_sortie;
unsigned char *chaine_sortie;
unsigned char *pointeur;
unsigned char *tampon;

if ((transcodage = iconv_open(codage_sortie, codage_entree)) = >> (iconv_t) -1)
{
return(NULL);
}

buffer_entree = chaine_entree;
longueur_entree = strlen(chaine_entree);

if ((chaine_sortie = malloc(sizeof(unsigned char))) == NULL)
{
return(NULL);
}


Par definition sizeof(char) == 1
chaine_sortie[0] = d_code_fin_chaine;

if ((buffer_sortie = malloc((d_LONGUEUR + 1) * sizeof(char))) == NULL)
{
return(NULL);
}


Si tu insistes pour faire du unsigned char *, pourquoi un sizeof(char) ici ?



Parce que c'est un oubli. Merci.

printf("> %dn", strlen(tampon)); // râlage de valgrind ici.



Ben deja, strlen renvoie un sizeof, donc une valeur pas signee, et pas forcement
un int de surcroit.

Je suis pas trop sur que valgrind rale pour les bonnes raisons, mais cette
ligne est passablement fausse. En C pre99, on ecrit:

printf("> %lun", (unsigned long)strlen(tampon));

et en C99:
printf("> %zun", strlen(tampon));



J'ai rajouté cette ligne pour débugguer, rapidement, ce matin. Si je
te mets un %lu à la place du %d, le résultat est le même.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Marc
JKB wrote:

Je viens de tomber sur un truc amusant avec valgrind



Ce n'est peut-être pas du tout le cas ici, mais un piège courant est
le suivant :

certaines fonctions sont écrites directement en assembleur pour des
raisons de performance. Il est plus rapide de lire par bloc que par
caractère. Des raisons d'alignement garantissent qu'il n'est pas
gênant de lire un bloc entier quand le début du bloc est alloué.
Valgrind n'est pas au courant de ces cas particuliers.
Avatar
JKB
Le Mon, 29 Aug 2011 11:34:38 +0000 (UTC),
Marc écrivait :
JKB wrote:

Je viens de tomber sur un truc amusant avec valgrind



Ce n'est peut-être pas du tout le cas ici, mais un piège courant est
le suivant :

certaines fonctions sont écrites directement en assembleur pour des
raisons de performance. Il est plus rapide de lire par bloc que par
caractère. Des raisons d'alignement garantissent qu'il n'est pas
gênant de lire un bloc entier quand le début du bloc est alloué.
Valgrind n'est pas au courant de ces cas particuliers.



Ça pourrait être une piste. Merci de l'indication.

Cordialement,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr