IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Allocation mémoire et addresses


Sujet :

C

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Points : 36
    Points
    36
    Par défaut Allocation mémoire et addresses
    Bonsoir,

    J'ai remarqué en executant le programme ci dessous que mon ordi allouait 2 fois la taille demandé pour une variable, si quelqu'un pouvait m'expliquer pourquoi..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdio.h>
    #include <string.h>
     
    int main(int argc, char *argv[]) {
       int value = 5;
       char buffer_one[8], buffer_two[8];
     
       strcpy(buffer_one, "one"); /* Put "one" into buffer_one. */
       strcpy(buffer_two, "two"); /* Put "two" into buffer_two. */
     
       printf("[BEFORE] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two);
       printf("[BEFORE] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one);
       printf("[BEFORE] value is at %p and is %d (0x%08x)\n", &value, value, value);
     
       printf("\n[STRCPY] copying %d bytes into buffer_two\n\n", (int)strlen(argv[1]));
       strcpy(buffer_two, argv[1]); /* Copy first argument into buffer_two. */
     
       printf("[AFTER] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two);
       printf("[AFTER] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one);
       printf("[AFTER] value is at %p and is %d (0x%08x)\n", &value, value, value);
    }
    Exemple d'execution:

    $ ./overflow_exemple 1234567890
    [BEFORE] buffer_two is at 0x7fff62e3d7c0 and contains 'two'
    [BEFORE] buffer_one is at 0x7fff62e3d7d0 and contains 'one'
    [BEFORE] value is at 0x7fff62e3d7bc and is 5 (0x00000005)

    [STRCPY] copying 10 bytes into buffer_two

    [AFTER] buffer_two is at 0x7fff62e3d7c0 and contains '1234567890'
    [AFTER] buffer_one is at 0x7fff62e3d7d0 and contains 'one'
    [AFTER] value is at 0x7fff62e3d7bc and is 5 (0x00000005)
    Les 16 premiers caractères sont insérés dans buffer_two alors que je ne lui ai alloué que 8 cases, la suite va dans buffer_one.
    Si quelqu'un peut m'eclaircir..

  2. #2
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Bonsoir.
    Chez moi, j'ai ceci :
    [BEFORE] buffer_two is at 0xbfebe034 and contains 'two'
    [BEFORE] buffer_one is at 0xbfebe02c and contains 'one'
    [BEFORE] value is at 0xbfebe028 and is 5 (0x00000005)

    [STRCPY] copying 10 bytes into buffer_two

    [AFTER] buffer_two is at 0xbfebe034 and contains '1234567890'
    [AFTER] buffer_one is at 0xbfebe02c and contains 'one'
    [AFTER] value is at 0xbfebe028 and is 5 (0x00000005)
    *** stack smashing detected ***: ./a.out terminated
    suivi d'informations de débogage...

    Je dirais que selon les compilateurs et les systèmes d'exploitation, on n'obtient pas le même résultat...
    Étonnant, dis donc !

    Plus sérieusement, je n'ai pas de réponse à ta question.

    Ubuntu Linux 11.10
    gcc 4.6.1

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    @Steph_ng8: Cela m'étonne que vous ne réagissez pas plus que cela. Il faut savoir que nos systèmes sont un peu touts différents, et pour ce cas là, les différences importantes sont :

    • le CPU (et sa gestion des erreurs?) ;
    • le noyau (et sa gestion des erreurs venant du CPU ou de sa mémoire) ;
    • les variables d'environnements (qui afissent sur le kernel, ou du moins, le contexte d'exécution) ;
    • le compilateur ;
    • l'état actuel de la mémoire.

    Bon bref, selon tout ces détails, les résultats diffèrent. Surtout que nous parlons d'un code à "comportement indéterminé". Donc, ce n'est pas qu'il faut s'attendre à un résultat précis, mais plutôt évité le problème à la racine.


    @Arkenis: Retour sur le problème. Votre programme ne plante pas, notamment car vous ne sortez pas de la page mémoire où votre programme est. (Enfin, j'avais lu un message de ce genre sur le forum). Il n'y a pas de crash, ce n'est qu'un hasard. Mais, sachez que cela peut crasher lamentablement, sur des systèmes plus frileux ou encore provoqué des comportements encore plus inattendus car vous écrasez de la mémoire d'un autre contexte (un autre programme par exemple).


    Donc, retenez surtout que : Votre code actuel est un code qui est "tombé en marche". Si vous le relancez, il se peut qu'il ne fonctionne plus. Il faut à tout prix évité ce genre d'erreur.
    Pour éviter ce genre d'erreur, nous avons la chance d'avoir valgrind. Ce programme détecte tout les problèmes liés à la mémoire (fuite de mémoire, écriture hors mémoire allouée, lecture hors mémoire allouée). Lancez votre petit programme dedans et vous allez voir comment valgrind râle (et il a raison).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Points : 36
    Points
    36
    Par défaut
    Bonjour,

    @Arkenis: Retour sur le problème. Votre programme ne plante pas, notamment car vous ne sortez pas de la page mémoire où votre programme est. (Enfin, j'avais lu un message de ce genre sur le forum). Il n'y a pas de crash, ce n'est qu'un hasard. Mais, sachez que cela peut crasher lamentablement, sur des systèmes plus frileux ou encore provoqué des comportements encore plus inattendus car vous écrasez de la mémoire d'un autre contexte (un autre programme par exemple).
    A vrai dire, ce que je ne comprends pas, c'est pourquoi les variables ne sont elles pas allouées sur des adresses adjacentes ? J'avais cru comprendre que le segment dans lequel les variables étaient rangées était continu et réservé a un seul programme.
    Le code ecrit plus haut est cité d'un livre dans lequel les caracteres d'indice supérieur a 8 sont placé dans la variable a l'adresse suivante..
    Cela veut-il dire que certaines configurations sont moins sensibles aux overflows que d'autres ?
    De plus, lorsqu'on alloue 8 "cases" pour un tableau, pourquoi celui ci prend les valeurs suivantes si ce sont des données d'un autre programme ?
    Enfin, apres plusieurs executions, l'écriture se fait sur le second buffer uniquement a partir du 16e caractere, où le "one" se transforme en "" puis prend les caracteres suivants.

    J'essaierais valgrind ce soir sur mon ordi.

  5. #5
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    @Steph_ng8: Cela m'étonne que vous ne réagissez pas plus que cela. Il faut savoir que nos systèmes sont un peu touts différents, et pour ce cas là, les différences importantes sont :

    • le CPU (et sa gestion des erreurs?) ;
    • le noyau (et sa gestion des erreurs venant du CPU ou de sa mémoire) ;
    • les variables d'environnements (qui afissent sur le kernel, ou du moins, le contexte d'exécution) ;
    • le compilateur ;
    • l'état actuel de la mémoire.

    Bon bref, selon tout ces détails, les résultats diffèrent. Surtout que nous parlons d'un code à "comportement indéterminé". Donc, ce n'est pas qu'il faut s'attendre à un résultat précis, mais plutôt évité le problème à la racine.
    Je ne vois pas très bien où tu (vous ?) veux en venir...
    enfin, je ne vois pas bien ce que tu (vous ?) veux me dire...

    Citation Envoyé par Arkenis Voir le message
    A vrai dire, ce que je ne comprends pas, c'est pourquoi les variables ne sont elles pas allouées sur des adresses adjacentes ? J'avais cru comprendre que le segment dans lequel les variables étaient rangées était continu et réservé a un seul programme.
    Il me semble que c'est le cas.
    Mais que se passe-t-il si tu tentes d'accéder à un endroit hors de l'espace réservé pour ce programme ?
    Si tu as de la chance, tu accèdes à une zone utilisée par aucun programme.
    Si tu n'as pas de chance, tu peux modifier l'espace mémoire d'un autre programme, et ainsi le rendre non cohérent, ce qui peut entraîner le plantage dudit programme.
    Et s'il s'agissait d'un programme système...

    Citation Envoyé par Arkenis Voir le message
    Cela veut-il dire que certaines configurations sont moins sensibles aux overflows que d'autres ?
    Je ne pense pas.
    C'est un phénomène très aléatoire, tout comme ses conséquences.

    Citation Envoyé par Arkenis Voir le message
    Enfin, apres plusieurs executions, l'écriture se fait sur le second buffer uniquement a partir du 16e caractere, où le "one" se transforme en "" puis prend les caracteres suivants.
    C'est certainement le but de ce programme.
    Chez moi, ça plante, mais chez ça va écrire des données dans l'espace mémoire d'une autre variable.
    Imagine que les variables de ce programme sont en réalité des programme d'un système, et tu te retrouves dans le cas que j'expliquais au-dessus...
    Ceci dit, je ne m'explique pas pourquoi il y a un « vide » entre les espaces réservés des variables.
    Cet espace est peut-être utilisé en interne...

    Par curiosité, tu es sur quel système d'exploitation, et tu utilises quel compilateur ?

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Points : 36
    Points
    36
    Par défaut
    Chez moi, ça plante, mais chez ça va écrire des données dans l'espace mémoire d'une autre variable.
    Oui mais si les segments de données sont bien continu, cette variable doit aussi appartenir au programme overflow_exemple dans le cas présent puisque une autre variable de ce programme est écrite dans une adresse supérieur non ?
    De plus, lorsqu'on affiche buffer_two, on demande a l'ordinateur d'afficher le contenu de 8 adresses et non 16.. ne devrait-on pas obtenir un resultat du genre:

    [AFTER] $ ./overflow_example 1234567890
    [BEFORE] buffer_two is at 0xbffff7f0 and contains 'two'
    [BEFORE] buffer_one is at 0xbffff7f8 and contains 'one'
    [BEFORE] value is at 0xbffff804 and is 5 (0x00000005)

    [STRCPY] copying 10 bytes into buffer_two
    [AFTER]buffer_two is at 0xbffff7f0 and contains '12345678' // Le 9 et le 0 sont dans des adresses comprises entre celles de buffer_one et buffer_two
    [AFTER] buffer_one is at 0xbffff7f8 and contains 'one'
    [AFTER] value is at 0xbffff804 and is 5 (0x00000005)
    Je cite le résultat donné dans le livre en question:

    $ gcc -o overflow_example overflow_example.c
    $ ./overflow_example 1234567890
    [BEFORE] buffer_two is at 0xbffff7f0 and contains 'two'
    [BEFORE] buffer_one is at 0xbffff7f8 and contains 'one'
    [BEFORE] value is at 0xbffff804 and is 5 (0x00000005)

    [STRCPY] copying 10 bytes into buffer_two

    [AFTER] buffer_two is at 0xbffff7f0 and contains '1234567890'
    [AFTER] buffer_one is at 0xbffff7f8 and contains '90'
    [AFTER] value is at 0xbffff804 and is 5 (0x00000005)
    Dans son cas aussi, buffer_one comprend plus de 8 caracteres, mais pourquoi ? le 90 est d'ailleurs retrouvé et dans buffer_one et dans buffer_two..

    J'utilise Ubuntu et je compile avec gcc

  7. #7
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Il n'y a aucun intérêt, sauf à tromper et perturber les lecteurs, à faire figurer ce genre de code dans un bouquin. A moins que ce soit dans un chapitre consacré à ce qu'il ne faut pas faire.
    Ecrire ce genre de choses est interdit en C.

    Il faut considérer que
    - Rien ne dit que les variables sont allouées dans des espaces mémoires contigus (sauf pour les éléments d'un tableau) (et ce n'est pas le cas en général pour des questions d'alignement)
    - Rien ne dit que les variables sont allouées dans l'espace mémoire en suivant l'ordre de leur définition (sauf pour les champs des structures). Le compilateur fait ce qui lui plait en ce domaine.
    - Ecrire ou lire des données dans un espace mémoire non alloué donne lieu a un comportement indéfini et tout peut arriver.

    lorsqu'on affiche buffer_two, on demande a l'ordinateur d'afficher le contenu de 8 adresses et non 16.. ne devrait-on pas obtenir un resultat du genre:....
    L'affichage se fait avec un printf("%s",...). La taille du buffer n'a pas d'importance pour l'affichage : il sort les caractères consécutivement jusqu'à trouver un '\0'
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Points : 36
    Points
    36
    Par défaut
    Ce code est effectivement placé dans un chapitre consacré aux overflows, avec des codes contenant des failles.

    Il faut considérer que
    - Rien ne dit que les variables sont allouées dans des espaces mémoires contigus (sauf pour les éléments d'un tableau) (et ce n'est pas le cas en général pour des questions d'alignement)
    - Rien ne dit que les variables sont allouées dans l'espace mémoire en suivant l'ordre de leur définition (sauf pour les champs des structures). Le compilateur fait ce qui lui plait en ce domaine.
    - Ecrire ou lire des données dans un espace mémoire non alloué donne lieu a un comportement indéfini et tout peut arriver.

    Citation:
    lorsqu'on affiche buffer_two, on demande a l'ordinateur d'afficher le contenu de 8 adresses et non 16.. ne devrait-on pas obtenir un resultat du genre:....
    L'affichage se fait avec un printf("%s",...). La taille du buffer n'a pas d'importance pour l'affichage : il sort les caractères consécutivement jusqu'à trouver un '\0'
    Merci beaucoup pour ces remarques, et ces réponses, ça résout mon problème !

Discussions similaires

  1. Pb d'allocation mémoire malloc
    Par oz80 dans le forum C++
    Réponses: 5
    Dernier message: 18/11/2005, 17h23
  2. Limite Allocation Mémoire d'un tableau d'entier
    Par l9ft b9hind dans le forum C++
    Réponses: 5
    Dernier message: 27/10/2005, 19h29
  3. Allocation mémoire
    Par DestyNov@ dans le forum C++
    Réponses: 9
    Dernier message: 23/08/2005, 08h09
  4. [Pointeur] Allocation mémoire
    Par Rayek dans le forum Langage
    Réponses: 22
    Dernier message: 20/05/2005, 10h26
  5. Allocation mémoire dynamique
    Par ITISAR dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 21/01/2005, 09h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo