Comportement surprenant de strcpy

Comportement surprenant de strcpy - C - Programmation

Marsh Posté le 09-03-2009 à 21:52:15    

Attention, question piège spécial experts.

 

Voici un programme tout con.
Si je compile (gcc 4)

Code :
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char *argv[])
  4. {
  5.     char src[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  6.     char dst[sizeof(src)] = "";
  7.     printf("sizeof src %d, sizeof dst %d\n", sizeof(src), sizeof(dst));
  8.     strcpy(dst, src);
  9.     printf("src %s %d\ndst %s %d\n", src, strlen(src), dst, strlen(dst));
  10.     return 0;
  11. }
 

Ca me sort:

 

sizeof src 37, sizeof dst 37
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36

 

Normal.

 

Maintenant, si je remplace la ligne 8 par
    char dst[sizeof(src)-1] = "";

 

A votre avis, que se passe-t'il à l'exécution ? Que me sort valgrind ?

 

Même question si je remplace la ligne par
    char dst[sizeof(src)-2] = "";

 

Appelez-moi noob, mais le résultat est tout de même assez surprenant.

Message cité 3 fois
Message édité par el muchacho le 09-03-2009 à 22:00:37

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 21:52:15   

Reply

Marsh Posté le 09-03-2009 à 21:55:06    

tu as oublié d'enlever le "-2" après le sizeof dans ton code :o

Message cité 1 fois
Message édité par sligor le 09-03-2009 à 21:55:26
Reply

Marsh Posté le 09-03-2009 à 21:56:32    

Sur ma plateforme (Linux x86), pour le premier cas, j'ai ceci:

 
Citation :

sizeof src 37, sizeof dst 36
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36

 

De plus, valgrind n'indique aucune erreur !

 

Dans le second cas, valgrind n'indique toujours aucune erreur !!!
Par contre, le runtime détecte une corruption de la pile.

 

J'ai exactement ceci:

 
Citation :


gromit:~/dev/SPString$ valgrind ./a.out
==6659== Memcheck, a memory error detector.
==6659== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==6659== Using LibVEX rev 1884, a library for dynamic binary translation.
==6659== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==6659== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==6659== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==6659== For more details, rerun with: -v
==6659==
sizeof src 37, sizeof dst 35
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36
*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0x41326d8]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0x4132690]
./a.out[0x80485d5]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0x404e685]
./a.out[0x80483f1]
======= Memory map: ========
04000000-0401a000 r-xp 00000000 08:21 4562977    /lib/ld-2.8.90.so
0401a000-0401b000 rw-p 0401a000 00:00 0
0401b000-0401c000 r--p 0001a000 08:21 4562977    /lib/ld-2.8.90.so
0401c000-0401d000 rw-p 0001b000 08:21 4562977    /lib/ld-2.8.90.so
0401d000-0401f000 rw-p 0401d000 00:00 0
0401f000-04020000 r-xp 00000000 08:21 4195119    /usr/local/lib/valgrind/x86-linux/vgpreload_core.so
04020000-04021000 r--p 00000000 08:21 4195119    /usr/local/lib/valgrind/x86-linux/vgpreload_core.so
04021000-04022000 rw-p 00001000 08:21 4195119    /usr/local/lib/valgrind/x86-linux/vgpreload_core.so
04022000-04029000 r-xp 00000000 08:21 4195138    /usr/local/lib/valgrind/x86-linux/vgpreload_memcheck.so
04029000-0402a000 r--p 00006000 08:21 4195138    /usr/local/lib/valgrind/x86-linux/vgpreload_memcheck.so
0402a000-0402b000 rw-p 00007000 08:21 4195138    /usr/local/lib/valgrind/x86-linux/vgpreload_memcheck.so
0402b000-0402c000 rw-p 0402b000 00:00 0
04038000-04190000 r-xp 00000000 08:21 4580349    /lib/tls/i686/cmov/libc-2.8.90.so
04190000-04192000 r--p 00158000 08:21 4580349    /lib/tls/i686/cmov/libc-2.8.90.so
04192000-04193000 rw-p 0015a000 08:21 4580349    /lib/tls/i686/cmov/libc-2.8.90.so
04193000-04196000 rw-p 04193000 00:00 0
041a3000-045a3000 rwxp 041a3000 00:00 0
045a3000-045b0000 r-xp 00000000 08:21 4562955    /lib/libgcc_s.so.1
045b0000-045b1000 r--p 0000c000 08:21 4562955    /lib/libgcc_s.so.1
045b1000-045b2000 rw-p 0000d000 08:21 4562955    /lib/libgcc_s.so.1
08048000-08049000 r-xp 00000000 08:21 4456618    /home/nicolas/dev/SPString/a.out
08049000-0804a000 r--p 00000000 08:21 4456618    /home/nicolas/dev/SPString/a.out
0804a000-0804b000 rw-p 00001000 08:21 4456618    /home/nicolas/dev/SPString/a.out
0804b000-0804c000 rwxp 0804b000 00:00 0
38000000-381c3000 r-xp 00000000 08:21 4195137    /usr/local/lib/valgrind/x86-linux/memcheck
381c4000-381c5000 rw-p 001c3000 08:21 4195137    /usr/local/lib/valgrind/x86-linux/memcheck
381c5000-388e3000 rw-p 381c5000 00:00 0
61fa2000-62b22000 rwxp 61fa2000 00:00 0
62b22000-62b24000 ---p 62b22000 00:00 0
62b24000-62b34000 rwxp 62b24000 00:00 0
62b34000-62b36000 ---p 62b34000 00:00 0
62b36000-64c93000 rwxp 62b36000 00:00 0
b8043000-b8044000 r-xp b8043000 00:00 0          [vdso]
bef41000-bef43000 rwxp bef41000 00:00 0
bff2f000-bff44000 rw-p bffeb000 00:00 0          [stack]
==6659==
==6659== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 14 from 2)
==6659== malloc/free: in use at exit: 0 bytes in 0 blocks.
==6659== malloc/free: 5 allocs, 5 frees, 908 bytes allocated.
==6659== For counts of detected errors, rerun with: -v
==6659== All heap blocks were freed -- no leaks are possible.
Aborted

 

Je n'arrive pas trop à m'expliquer ce comportement.


Message édité par el muchacho le 09-03-2009 à 23:14:51

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 21:59:41    

sligor a écrit :

tu as oublié d'enlever le "-2" après le sizeof dans ton code :o


Oups, corrigé.


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:05:47    

moi dans le "-1" j'ai:

Citation :

sizeof src 37, sizeof dst 36
src  0
dst abcdefghijklmnopqrstuvwxyz0123456789 36

 

valgrind râle:

Citation :


==13532== Source and destination overlap in strcpy(0xBEFDE4E7, 0xBEFDE50B)
==13532==    at 0x402457D: strcpy (mc_replace_strmem.c:268)
==13532==    by 0x80484D6: main (test.c:11)

 

et dans le "-2" j'ai:

Citation :


./a.out
sizeof src 37, sizeof dst 35
src 9 1
dst abcdefghijklmnopqrstuvwxyz0123456789 36

 

valgrind râle:

Citation :


==13553== Source and destination overlap in strcpy(0xBEB114E8, 0xBEB1150B)
==13553==    at 0x402457D: strcpy (mc_replace_strmem.c:268)
==13553==    by 0x80484F1: main (test.c:11)

 

chez moi c'est beaucoup plus compréhensible  :D

 

je dirais que dans ta pile src et dst sont inversés par rapport à la mienne

 

edit: tu peux essayer de rajouter printf("dst-src=%d\n",dst-src); pour voir ?

Message cité 1 fois
Message édité par sligor le 09-03-2009 à 22:07:51
Reply

Marsh Posté le 09-03-2009 à 22:08:44    

Euh, c'est bien le même programme, là ? Parce que l'overlap, je vois vraiment pas pourquoi [:pingouino]


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:11:56    

el muchacho a écrit :

Euh, c'est bien le même programme, là ? Parce que l'overlap, je vois vraiment pas pourquoi [:pingouino]


si dst est juste avant src dans la pile, ce qui est le cas chez moi

Message cité 1 fois
Message édité par sligor le 09-03-2009 à 22:12:22
Reply

Marsh Posté le 09-03-2009 à 22:12:58    

sligor a écrit :


edit: tu peux essayer de rajouter printf("dst-src=%d\n",dst-src); pour voir ?


Code :
  1. ...
  2. printf("dst-src=%d\n",dst-src);
  3. strcpy(dst, src);
  4. printf("dst-src=%d\n",dst-src);
  5. ...


 
Résultat:
dst-src=-37
dst-src=-37
(résultat attendu)


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:14:21    

sligor a écrit :


si dst est juste avant src dans la pile, ce qui est le cas chez moi


Ah oui, ok, pas con. C'est quoi, ta machine, à titre indicatif ?


Message édité par el muchacho le 09-03-2009 à 22:15:38

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:19:06    

el muchacho a écrit :


Code :
  1. ...
  2. printf("dst-src=%d\n",dst-src);
  3. strcpy(dst, src);
  4. printf("dst-src=%d\n",dst-src);
  5. ...
 

Résultat:
dst-src=-37
dst-src=-37
(résultat attendu)


donc tu as aussi dst avant src, tu as la même organisation de pile que moi, du coup je ne comprends pas pourquoi tu n'as pas 0 et 1 comme longueur de dst avec "-1" et "-2", à moins que le compilateur change l'organisation sur les autres valeurs.
Tu peux aussi tester avec les "-1" et "-2" ?

 

ma config: debian lenny, gcc 4.3.2, x86 32bits

Message cité 1 fois
Message édité par sligor le 09-03-2009 à 22:20:03
Reply

Marsh Posté le 09-03-2009 à 22:19:06   

Reply

Marsh Posté le 09-03-2009 à 22:20:07    

Y a quoi de surprenant dans un UB ?

Reply

Marsh Posté le 09-03-2009 à 22:22:06    

sligor a écrit :


ma config: debian lenny, gcc 4.3.2, x86 32bits


J'ai la même version de gcc que toi, sous Ubuntu.

Citation :

Tu peux aussi tester avec les "-1" et "-2" ?


J'obtiens la même chose qu'avant.

Taz a écrit :

Y a quoi de surprenant dans un UB ?


Un quoi ??


Message édité par el muchacho le 09-03-2009 à 22:24:42

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:34:01    

el muchacho a écrit :


A votre avis, que se passe-t'il à l'exécution ?

 

Tu altères la pile, et le résultat est "indéfini" (dépendant de comment le compilateur va optimiser le code, l'ordre des variables, et probablement l'architecture aussi). Le seul moyen de vraiment en être sur, c'est de regarder le code compilé.

 
el muchacho a écrit :

Que me sort valgrind ?

 

Valgrind a beaucoup de mal à détecter le petage de pile, vu qu'il ne fait pas de bound checking sur des agrégats en pile ou statique.

 

C'est particulièrement difficile à détecter de toute manière, il n'y a pas autant de liberté que dans le tas ou on peut facilement placer des tokens ou des pages invalides pour provoquer des fautes d'accès.

 

Ce cas là de toute manière, tu peux l'empecher avec des canary. Compile avec -fstack-protector...

Message cité 2 fois
Message édité par Gf4x3443 le 09-03-2009 à 22:34:53

---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 09-03-2009 à 22:35:45    

el muchacho a écrit :

Attention, question piège spécial experts.

 

Voici un programme tout con.
Si je compile (gcc 4)

Code :
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char *argv[])
  4. {
  5.     char src[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  6.     char dst[sizeof(src)] = "";
  7.     printf("sizeof src %d, sizeof dst %d\n", sizeof(src), sizeof(dst));
  8.     strcpy(dst, src);
  9.     printf("src %s %d\ndst %s %d\n", src, strlen(src), dst, strlen(dst));
  10.     return 0;
  11. }
 

Ca me sort:

 

sizeof src 37, sizeof dst 37
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36

 

Normal.

 

Maintenant, si je remplace la ligne 8 par
    char dst[sizeof(src)-1] = "";

 

A votre avis, que se passe-t'il à l'exécution ? Que me sort valgrind ?

 

Même question si je remplace la ligne par
    char dst[sizeof(src)-2] = "";

 

Appelez-moi noob, mais le résultat est tout de même assez surprenant.

 

Rien de surprenant.

 

Les deux résultats sont identiques avec -1 et -2 (aléatoirement), et valgrind devrait te sortir un truc du genre "read out of bound" ou ce genre de chose.

 

strcpy() recopie src dans dst jusqu'à trouver un '\0'. Sans se préoccuper de la taille de dst. Donc ça recopie src dans dst en dépassant les capacités de cette dernière variable.

 

edit : ah ok j'avais pas lu la suite, et je me serais attendu aussi à ce que valgrind râle. Oubliez mon post qui arrive comme un cheveu sur la soupe. [:prozac]


Message édité par Elmoricq le 09-03-2009 à 22:37:13
Reply

Marsh Posté le 09-03-2009 à 22:36:49    

Gf4x3443 a écrit :

 

Tu altères la pile, et le résultat est "indéfini" (dépendant de comment le compilateur va optimiser le code, l'ordre des variables, et probablement l'architecture aussi). Le seul moyen de vraiment en être sur, c'est de regarder le code compilé.

 



sauf que si dst-src=-37 il ne peut pas péter la pile avec ce qu'il fait  :o
donc j'aimerais bien qu'il revérifie avec sizeof(src)-1 et sizeof(src)-2  :o

Message cité 1 fois
Message édité par sligor le 09-03-2009 à 22:49:50
Reply

Marsh Posté le 09-03-2009 à 22:37:05    

Undefined Behaviour

Reply

Marsh Posté le 09-03-2009 à 22:42:25    

Gf4x3443 a écrit :


Tu altères la pile, et le résultat est "indéfini" (dépendant de comment le compilateur va optimiser le code, l'ordre des variables, et probablement l'architecture aussi). Le seul moyen de vraiment en être sur, c'est de regarder le code compilé.


:jap:

 
Citation :

Valgrind a beaucoup de mal à détecter le petage de pile, vu qu'il ne fait pas de bound checking sur des agrégats en pile ou statique.

 

C'est particulièrement difficile à détecter de toute manière, il n'y a pas autant de liberté que dans le tas ou on peut facilement placer des tokens ou des pages invalides pour provoquer des fautes d'accès.


C'est ce que je me disais aussi.

 
Citation :

Ce cas là de toute manière, tu peux l'empecher avec des canary. Compile avec -fstack-protector...


:jap: je vais essayer ça.

Taz a écrit :

Undefined Behaviour


OK.

sligor a écrit :


sauf que si dst-src=-37 il ne peut pas péter la pile avec ce qu'il fait  :o
donc j'aimerais bien qui revérifie avec sizeof(src)-1 et sizeof(src)-2  :o


J'ai 37 à chaque fois, et j'ai la même chose qu'auparavant pour le reste du code.
Et par ailleurs, j'ai la même version de gcc que toi.


Message édité par el muchacho le 09-03-2009 à 22:46:48

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:45:19    

Ah ouais, tiens, dans le même genre. Qu'est ce qu'il y a de foireux avec ce code :
 

Code :
  1. char version[4];
  2. if (sscanf("1.9.0.2", "%hhu.%hhu.%hhu.%hhu", version, version+1, version+2, version+3) == 4)
  3. {
  4.     // Plantage probable.
  5. }


Spoiler :

En fait il n'y a rien de vraiment faux dans ce code.
 
Par contre sous Windows, avec certaine version de la msvcrt le %hhu est interprété comme un %u. Dans ce cas là, dès le "version+1", il y stack overflow. Je suis bouffé des plantages complètement aléatoires dans des portions de codes à des kilomètres de l'erreur, avec une compilation en -O2 ou -O3 sous MinGW, alors qu'en -O0, ça passait sans le moindre problème.
 
Une demi journée de débuguage  :sweat:

Reply

Marsh Posté le 09-03-2009 à 22:49:04    

Ah putaing, cong, en fait, sligor a raison : avec le -1, j'ai +37 ! gcc change l'ordre des chaînes dans la pile !


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:51:13    

donc du coup la corruption de pile est plus logique, tout s'explique :jap:

Reply

Marsh Posté le 09-03-2009 à 22:52:15    

Reply

Marsh Posté le 09-03-2009 à 22:52:35    

tpierron a écrit :

Ah ouais, tiens, dans le même genre. Qu'est ce qu'il y a de foireux avec ce code :
Une demi journée de débuguage  :sweat:

 

Ayé, je compatis. J'ai eu aussi des problèmes avec des LARGE_INTEGER avec MinGW. Je me rappelle avoir passé ma semaine à essayer de comprendre pourquoi je n'avais pas de bonnes valeurs affichées dans des printf().

 

En fait, c'est là tout le challenge: entre un code source et le code compilé, c'est non trivial de qualifier du code aujourd'hui. Enfin du moins, dans de l'embarqué, ca m'a valu quelques crises :/

Message cité 1 fois
Message édité par Gf4x3443 le 09-03-2009 à 22:53:03

---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 09-03-2009 à 22:53:16    

tpierron a écrit :

Ah ouais, tiens, dans le même genre. Qu'est ce qu'il y a de foireux avec ce code :

 
Code :
  1. char version[4];
  2. if (sscanf("1.9.0.2", "%hhu.%hhu.%hhu.%hhu", version, version+1, version+2, version+3) == 4)
  3. {
  4.     // Plantage probable.
  5. }


Spoiler :

En fait il n'y a rien de vraiment faux dans ce code.

 

Par contre sous Windows, avec certaine version de la msvcrt le %hhu est interprété comme un %u. Dans ce cas là, dès le "version+1", il y stack overflow. Je suis bouffé des plantages complètement aléatoires dans des portions de codes à des kilomètres de l'erreur, avec une compilation en -O2 ou -O3 sous MinGW, alors qu'en -O0, ça passait sans le moindre problème.

 

Une demi journée de débuguage  :sweat:


 

Hm. C'est pas un problème de norme plutôt ? Je zone les manpages depuis 5min, et il y en a avec hh, et d'autres sans.
Pour rire j'ai regardé sur Solaris 8 (ok, côté norme c'est pas ce qu'il y a de plus strict cet OS :/ ), pas de hh. Sur Solaris 10 par contre, il y est.

 

edit : trouvé. "hh" c'est bien C99, d'où les différences de comportement avec certains compilateurs pas à jour.

Message cité 1 fois
Message édité par Elmoricq le 09-03-2009 à 22:57:16
Reply

Marsh Posté le 09-03-2009 à 22:53:40    

Sinon, le -fstack-protector, j'ai pas trop vu son effet. :/


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:57:21    

Gf4x3443 a écrit :


Ayé, je compatis. J'ai eu aussi des problèmes avec des LARGE_INTEGER avec MinGW. Je me rappelle avoir passé ma semaine à essayer de comprendre pourquoi je n'avais pas de bonnes valeurs affichées dans des printf().
 
En fait, c'est là tout le challenge: entre un code source et le code compilé, c'est non trivial de qualifier du code aujourd'hui. Enfin du moins, dans de l'embarqué, ca m'a valu quelques crises :/


Clair, ce qu'il y a de bien avec le C, c'est que c'est supêr simple, mais on peut passer une vie entière sur ce genre de conneries.:/


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 22:57:22    

Elmoricq a écrit :

 

Hm. C'est pas un problème de norme plutôt ? Je zone les manpages depuis 5min, et il y en a avec hh, et d'autres sans.
Pour rire j'ai regardé sur Solaris 8 (ok, côté norme c'est pas ce qu'il y a de plus strict cet OS :/ ), pas de hh. Sur Solaris 10 par contre, il y est.


d'où l'utilité de l'option "-pedantics" avec gcc
mais sur un gros projet développé sans cette option dés le dépat, on a vite d'innombrables warnings

Citation :


 gcc -g test.c -Wall -ansi -pedantic
test.c: In function ‘main’:
test.c:7: warning: ISO C90 does not support the ‘hh’ scanf length modifier
test.c:7: warning: format ‘%hhu’ expects type ‘unsigned char *’, but argument 3 has type ‘char *’
test.c:7: warning: ISO C90 does not support the ‘hh’ scanf length modifier
test.c:7: warning: format ‘%hhu’ expects type ‘unsigned char *’, but argument 4 has type ‘char *’
test.c:7: warning: ISO C90 does not support the ‘hh’ scanf length modifier
test.c:7: warning: format ‘%hhu’ expects type ‘unsigned char *’, but argument 5 has type ‘char *’
test.c:7: warning: ISO C90 does not support the ‘hh’ scanf length modifier
test.c:7: warning: format ‘%hhu’ expects type ‘unsigned char *’, but argument 6 has type ‘char *’



Message édité par sligor le 09-03-2009 à 22:58:42
Reply

Marsh Posté le 09-03-2009 à 22:57:51    

J'ai édité mon post 4s avant ta réponse. [:klem3i1]

Reply

Marsh Posté le 09-03-2009 à 23:02:28    

Il n'aborte pas avec -1?
 

toulouse$ grep "dst" test.c              
    char dst[sizeof(src) - 1] = "";
    printf("sizeof src %d, sizeof dst %d\n", sizeof(src), sizeof(dst));
    strcpy(dst, src);
    printf("src %s %d\ndst %s %d\n", src, strlen(src), dst, strlen(dst));
toulouse$ cc -fstack-protector -o test test.c    
toulouse$ ./test                                                                
sizeof src 37, sizeof dst 36
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36
Program received signal SIGABRT, Aborted.


---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 09-03-2009 à 23:06:14    

c'est indéterminé ça dépends de plein de choses, on était plus parti pour comprendre ce qu'il se passait plus exactement sur la machine de el muchacho


Message édité par sligor le 09-03-2009 à 23:06:33
Reply

Marsh Posté le 09-03-2009 à 23:08:46    

Chez moi, il n'en a rien à secouer. Je suppose que c'est exactement pour la même raison qu'au-dessus, à savoir que l'ordre des chaînes sur la pile est bizarrement inversé quand je réduis la taille de dst. Ce qui est bizarre, c'est que gcc se comporte comme ça que chez moi (avec les options de compilation par défaut).


Message édité par el muchacho le 09-03-2009 à 23:09:53

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 09-03-2009 à 23:10:35    

Ca c'est fun. C'est quelle version 4 de gcc? 4.1.2 ici (sous NetBSD), pas d'inversion dans les adresses des tableaux, ca fait -37, -36, -35, ... quand je réduis dst.


Message édité par Gf4x3443 le 09-03-2009 à 23:11:48

---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 09-03-2009 à 23:14:20    

Citation :

gromit:~/dev/SPString$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.2-1ubuntu12' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)


 
Le plus marrant, c'est que c'est le même compilo que sligor, et chez lui, il n'obitent pas la même chose.
sligor, ça donne quoi, chez toi
gcc -v  
?


Message édité par el muchacho le 09-03-2009 à 23:17:03

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 10-03-2009 à 08:24:39    

el muchacho a écrit :

Attention, question piège spécial experts.
 
Voici un programme tout con.
Si je compile (gcc 4)

Code :
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char *argv[])
  4. {
  5.     char src[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  6.     char dst[sizeof(src)] = "";
  7.     printf("sizeof src %d, sizeof dst %d\n", sizeof(src), sizeof(dst));
  8.     strcpy(dst, src);
  9.     printf("src %s %d\ndst %s %d\n", src, strlen(src), dst, strlen(dst));
  10.     return 0;
  11. }


 
Ca me sort:
 
sizeof src 37, sizeof dst 37
src abcdefghijklmnopqrstuvwxyz0123456789 36
dst abcdefghijklmnopqrstuvwxyz0123456789 36
 
Normal.
 
Maintenant, si je remplace la ligne 8 par
    char dst[sizeof(src)-1] = "";


Le comportement est indéfini. tout peut arriver.
 

Citation :

A votre avis, que se passe-t'il à l'exécution ? Que me sort valgrind ?


Personne ne peut le prévoir. Mais le code est faux, c'est certain.

Citation :


Même question si je remplace la ligne par  
    char dst[sizeof(src)-2] = "";
 
Appelez-moi noob, mais le résultat est tout de même assez surprenant.


Je ne sais pas de quel résultat tu parles, mais on a pas à s'étonner d'un comportement indéfini. Je répète TOUT peut arriver, y compris un comportement d'apparence normale.
 
Un code est correct si
 
1 - il est écrit correctement
2 - il se comporte comme prévu.
 
Si le #1 est faux tout le reste est sans objet.


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 10-03-2009 à 08:32:29    

tpierron a écrit :

En fait il n'y a rien de vraiment faux dans ce code.
 
Par contre sous Windows, avec certaine version de la msvcrt<...>


C'est pas un problème de codage, mais de bibliothèque C sous Windows qui, rappelons le une bonne fois pour toute : ne supporte pas C99...  
(même si certaines concessions semblent avoir été faites sous Vista SP1, comme le support de "%ll*" )


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 10-03-2009 à 22:06:43    

Emmanuel Delahaye a écrit :


C'est pas un problème de codage, mais de bibliothèque C sous Windows qui, rappelons le une bonne fois pour toute : ne supporte pas C99...  
(même si certaines concessions semblent avoir été faites sous Vista SP1, comme le support de "%ll*" )

Le pire c'est que j'avais fait un test rapide pour voir si ça fonctionnait. Comme l'ordre des octets était little-endian, la seule chose qui merdait était le stack overflow (que je n'avais pas pensé à vérifié dans mon test). En big endian, j'aurais vu directement le problème, puisque tout aurait valu 0 (vu que je convertissais des nombres < 10). En fait, le comportement que j'attendais était que le code de retour reflète les formats de conversion non reconnu, jamais j'aurais imaginé que cette lib puisse écrire un int dans un char :/.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed