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 :

test fonction malloc


Sujet :

C

  1. #1
    Futur Membre du Club
    Inscrit en
    Janvier 2006
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 26
    Points : 8
    Points
    8
    Par défaut test fonction malloc
    Bonjour


    Je voudrais tester la fonction malloc en allouant 2 espaces mémoire et essayer de faire déborder le premier sur le second :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = malloc(2*sizeof(int));
    allocatedMem2 = malloc(2*sizeof(int));
    Je voudrais remplir le premier tableau (*allocatedMem1) pour le faire déborder sur le second (*allocatedMem1) et visualiser.


    Merci de votre aide

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par skyman272 Voir le message
    Je voudrais remplir le premier tableau (*allocatedMem1) pour le faire déborder sur le second (*allocatedMem1) et visualiser.
    Bonjour

    allocatedMem1 et allocatedMem2 contiennent 2 adresses qui sont situées sur un même plan. Donc tu peux calculer leur distance (en octets) et vérifier laquelle est placée avant laquelle. Ensuite te suffit d'écrire le bon nombre d'octets dans la première pour atteindre la seconde...

    [edit] toutefois (merci à obsidian qui m'a rappelé ce détail) rien ne dit qu'entre la première et la seconde il n'y aura pas de zone "interdite" qui entraineront alors un comportement indéterminé lors de l'accès...
    Effectivement son idée est meilleure: allouer une seule grosse zone dans allocatedMem1 et placer ensuite allocatedMem2 à un endroit défini de la zone. Puis remplir allocatedMem1 et regarder l'effet que ça aura sur allocatedMem2 quand le remplissage atteint ce point...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Bonjour,

    Ce n'est pas possible avec la fonction malloc() elle-même, qui est justement conçue pour garantir que cela n'arrive jamais.

    Par contre, tu peux essayer de dépasser volontairement la taille de ce que tu as alloué pour voir dans quoi tu vas taper. Tu vas alors entrer dans le domaine des « comportements indéfinis » (c'est-à-dire non imposés par la norme). Il n'y a rien qui te garantit que les segments alloués vont forcement localisés le second après le premier, ni même qu'ils seront consécutifs et sans gap entre les deux. Mais si c'est le cas, tu enchaîneras de l'un à l'autre sans que ton programme ne se doute de rien.

    Si tu veux faire des exercices sur les dépassements de buffer en général, alors tu peux également déclarer un seul segment de mémoire, y placer des pointeurs de tableaux définis par tes soins et à des endroits arbitraires, puis t'amuser à dépasser ces tableaux volontairement. Tu verras alors ton programme écraser ce qui se trouve après ces tableaux et, donc, écrire des valeurs complètement indéfinies dans les variables adjacentes.

  4. #4
    Futur Membre du Club
    Inscrit en
    Janvier 2006
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 26
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour

    allocatedMem1 et allocatedMem2 contiennent 2 adresses qui sont situées sur un même plan. Donc tu peux calculer leur distance (en octets) et vérifier laquelle est placée avant laquelle. Ensuite te suffit d'écrire le bon nombre d'octets dans la première pour atteindre la seconde...

    Si j'ecrit ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = malloc(2*sizeof(char));
    allocatedMem2 = malloc(2*sizeof(char));
    (si je fais la différence entre les 2 pointeurs il y a 8 octets d'écart )

    Ensuite je remplis les 2 buffers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = "123456789101112";
    allocatedMem2 = "ABCDEFGHIJKL";
    Et j'affiche le contenu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    printf("variable pointer1=%s\n", allocatedMem1);
    printf("variable pointer2=%s\n", allocatedMem2);
    le resultat est :

    variable pointer1=123456789101112
    variable pointer2=ABCDEFGHIJKL
    Je ne comprend pas, j'ai alloué en mémoire 2 buffers de 2 octets, donc la premiere chaine devrait etre tronquée et devrait dépassé sur la deuxieme, non ?????

    Je devrais avoir quelque chose comme :

    variable pointer1=12
    variable pointer2=34
    Quelqu'un peut il m'expliquer ???

    Merci

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par skyman272 Voir le message
    Si j'ecrit ça :
    (si je fais la différence entre les 2 pointeurs il y a 8 octets d'écart )
    Oui, parce qu'il y a une granularité minimum. Tu ne peux pas affecter sans perte d'espace des plages aussi minces.

    Ensuite je remplis les 2 buffers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = "123456789101112";
    allocatedMem2 = "ABCDEFGHIJKL";
    le resultat est :

    variable pointer1=123456789101112
    variable pointer2=ABCDEFGHIJKL
    Je ne comprend pas, j'ai alloué en mémoire 2 buffers de 2 octets, donc la premiere chaine devrait etre tronquée et devrait dépassé sur la deuxieme, non ?????
    Je devrais avoir quelque chose comme :

    variable pointer1=12
    variable pointer2=34
    Tu ne peux pas copier une chaîne d'un buffer à l'autre avec « = », qui est géré par le compilateur, et fonctionne avec des types de taille fixe, si possible réduite, et surtout connue à l'avance. Il faut utiliser strcpy() à la place.

    Lorsque tu écris ce que tu as écrit, tu affectes l'adresse en mémoire de chaque chaîne au pointeur correspondant. Ces chaînes sont définies au moment de la rédaction de ton programme et se retrouvent donc à faire partie du code. Elles sont donc chargées en mémoire à lecture seule en même temps que le reste et, donc, sont lisibles depuis l'endroit où elles se trouvent. Mais il n'y a pas réplication. Seule aura été copiée leur adresse d'implantation et même, là encore, comme c'est le compilateur qui décide à l'avance où il va les placer et que c'est aussi lui qui génère le code qui charge tes pointeurs, il est tout-à-fait probable, au niveau du code assembleur, que cela se traduise par le chargement dans un registre d'une constante fixe, calculée à l'avance.

    En outre, dans l'exemple que tu nous as donné, tu aurais provoqué un dépassement de buffer. En effet, l'allocation d'une plage mémoire ne fait que réserver une zone contiguë en mémoire, en la répertoriant quelque part pour éviter qu'elle soit également attribué à quelque chose d'autre. Ce n'est pas un objet managé en soi, et il n'y a pas de méta-information que l'on puisse interroger a posteriori pour en connaître la taille, par exemple. Donc, il n'y aura pas de garde-fou pour stopper une copie de chaîne trop longue, par exemple, sauf à les mettre en place soi-même, par exemple avec strncpy().

    Le problème sera également le même avec des tableaux, déclarés sur la pile.

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par skyman272 Voir le message
    Si j'ecrit ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = malloc(2*sizeof(char));
    allocatedMem2 = malloc(2*sizeof(char));
    Ensuite je remplis les 2 buffers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    allocatedMem1 = "123456789101112";
    allocatedMem2 = "ABCDEFGHIJKL";
    Quelqu'un peut il m'expliquer ???
    Ben déjà quand tu écris var=truc puis 2 lignes plus loin var=autre_chose déjà tu devrais immédiatement te rendre compte qu'il y a un sacré soucis (qu'est devenu "truc" ???).

    Pour faire des essais sur le comportement de tel ou tel outil, il faut au minimum maitriser la base !!! On ne remplit pas un tableau (ou une zone mémoire) avec "=" !!! (enfin si on le fait mais on le fait sur les octets de la zone et non sur la zone elle même !!!)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Si tu veux constater ce qui se passe lorsque tu outrepasses les limites d'adressage de manière fiable et déterminée, la seule solution est d'encapsuler ton test dans un système d'allocation virtuelle comme te l'a proposé Obsidian.

    Car en conditions réelles, faire cela entraîne un comportement par définition indéterminé : on peut constater un résultat mais l'expérience n'étant pas déterministe on ne peut pas en déduire grand chose dans le cas général et l'intérêt est limité.

    Cela dit ça peut être amusant.. un peu de stack smashing :

    Code smash.c : 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
    22
    23
    #include <limits.h>
    #include <stdio.h>
    #include <string.h>
     
     
    int main(int argc, char *argv[]) {
        char password[] = "rainbow";
        char guess[8];
     
        printf("enter password: ");
        fgets(guess, INT_MAX, stdin);
     
        // get rid of final '\n'
        size_t guess_len = strlen(guess);
        if (guess_len > 0 && guess[guess_len - 1] == '\n')
            guess[guess_len - 1] = '\0';
     
        printf(strcmp(password, guess) == 0 ? "access granted\n" : "access denied\n");
     
        printf("\npassword: '%s'\nguess: '%s'\n", password, guess);
     
        return 0;
    }

    Comportement sur ma machine (compiler sans la protection de pile ; le caractère nul s'obtient le plus souvent avec ctrl + espace : ^@) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ gcc -std=c11 -pedantic -Wall -Wextra -fno-stack-protector smash.c
    $ ./a.out
    enter password: ???
    access denied
     
    password: 'rainbow'
    guess: '???'
    $ ./a.out
    enter password: ^@1234567^@
    access granted
     
    password: ''
    guess: ''

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    allocatedMem1 et allocatedMem2 contiennent 2 adresses qui sont situées sur un même plan. Donc tu peux calculer leur distance (en octets) et vérifier laquelle est placée avant laquelle.
    En fait, rien que ça, du point de vue de la norme, c'est un comportement indéfini. En revanche, si tu les convertis en intptr_t avant, ça devient implementation-defined...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Réponses: 20
    Dernier message: 13/02/2007, 11h50
  2. Fonction malloc pour allocation
    Par Maria1505 dans le forum C
    Réponses: 6
    Dernier message: 06/11/2006, 16h38
  3. fonction malloc en c
    Par Invité(e) dans le forum C
    Réponses: 2
    Dernier message: 15/04/2006, 23h34

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