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 :

Adresse et taille d'un tableau statique


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut Adresse et taille d'un tableau statique
    Bonjour,

    Je cherche un moyen de récupérer la taille d'un tableau statique déclarée comme cela :
    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
     
    int foo(char* buffer /* char buffer[1024] */)
    {
       // Affiche 4 la taille du pointeur mais je voudrais en fait récupérer 1024
       printf("sizeof(buf) = %d\n", sizeof(buf));
    }
    int main()
    { 
        char buffer[1024];
     
        // Affiche bien 1024
        printf("sizeof(buf) = %d\n", sizeof(buffer));
     
        foo(buffer);
     
        ...
    }
    Question 1 : Peux t-on récupérer la taille du buffer sans passer la taille en paramètre à la fonction foo ?
    Question 2 : Où est stocké l'adresse et la taille de buffer ? Dans le fichier objet, le fichier binaire ou alors déterminé au runtime ? De manière à pouvoir la récupérer quelque part...

    En fait, je voudrais savoir si les adresses (et leur taille dans mon exemple 1024) des tableaux statiques sont stockées dans le fichier main.o ou alors dans le binaire final main.exe ?

    Je travaille sous Windows 7, je sais que chaque programme dispose d'un espace de mémoire virtuelle, mais je ne sais pas trop comment cela marche.

    Merci d'avance et bonne journée
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Membre très actif

    Femme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    591
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 591
    Par défaut
    Bonjour,

    Question 1 : Peux t-on récupérer la taille du buffer sans passer la taille en paramètre à la fonction foo ?
    Non

    Question 2 : Où est stocké l'adresse et la taille de buffer ?
    Null part elle est juste connue à la compilation, dans cas de buffer[1024]
    Sinon l’adresse est renvoyée par malloc dans le cas d'une allocation dynamique du tableau

    De manière à pouvoir la récupérer quelque part...
    buffer est l'adresse de début du tableau
    printf("0x%p\n",buffer);

  3. #3
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    D'accord

    Null part elle est juste connue à la compilation, dans cas de buffer[1024]
    Et justement, est-il possible de la récupérer ? (soit pendant le processus de compilation ou alors dans un fichier intermédiaire ?)

    Pour les allocations dynamiques, je n'ai aucun problème puisque je peux surcharger la fonction malloc et récupérer toutes les infos que je veux (adresse et taille notamment) mais pour les tableaux statiques, c'est plus compliqué...

    En fait le but serait de faire une map des tableaux statiques présent dans un fichier source .C en disant :
    buffer => adresse 0x0000ABCD, taille = 1024
    buffer2 => adresse 0x0000BBBB, taille = 128
    ...


    afin de détecter d'éventuels buffer overflow/underflow sur des buffers statiques (je sais qu'il existe des outils pour cela mais je voudrais comprendre par moi même et me créer mon propre outil). Etant donné que CPPcheck le fais déjà, il doit bien y avoir une solution pour savoir à l'avance les adresses et tailles des tableaux statiques non ?

    Merci
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  4. #4
    Membre très actif

    Femme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    591
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 591
    Par défaut
    buffer => adresse 0x0000ABCD, taille = 1024
    buffer2 => adresse 0x0000BBBB, taille = 128
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    printf("buffer => adresse 0x%p, taille = %d\n,"buffer,BUFFER_SIZE);
    printf("buffer2 => adresse 0x%p, taille = %d\n,"buffer2,BUFFER2_SIZE);
    En fait quand je dis que l'adresse st stockée null part, quelque part c'est faux.
    buffer est l'adresse du tableau nommé buffer.
    Mais quand tu fais printf("buffer:0x%p\n",buffer), le compilo remplace buffer par une constante connue à la compilation.
    Cette constante est stockée nulle part, mais cela ne veut pas dire que tu ne peux pas connaitre sa valeur.
    Si vraiment tu veux une variable rien ne t’empêche de faire char *const addresse_de_buffer = buffer;

  5. #5
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    En fait quand tu declares un tableau sur la stack, tu ne fais que ajouter a la taille reservee pour la stack frame. Mais c'est la somme totale de la taille des variables qui est reservee.

    Par exemple, sur 32 bits, si tu as:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int a;
    int b;
    char buf[1024]
    le compilo va reserver le tout en prologue de fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mov ebp, esp
    sub esp, 0x408
    ou 0x408 est egal 1024 + sizeof(int) + sizeof(int). Je simplifie car ce chiffre varie en fonction du padding/alignement introduit par le compilo, ainsi que des valeurs utiles pour depiler la stack (saved ebp, saved eip).

    Donc en gros au runtime, tu ne peux pas savoir en examinent simplement la stack quelle est la taille de ton tableau. Tu as seulement la taille totale occupee par les variables locales.

    Citation Envoyé par Aspic Voir le message
    Et justement, est-il possible de la récupérer ? (soit pendant le processus de compilation ou alors dans un fichier intermédiaire ?)
    A la pre-compilation ou avant la compilation c'est possible. Je sais pas exactement comment. C'est exactement ce que fait FORTIFY_SOURCE sur gcc. Il analyse le code source ou intermediaire, determine la taille des tableaux et reordonne la declaration des variables. Les tableaux sont positionnes au dessus des variables locales, pour eviter qu'en cas d'overflow on puisse ecraser une variable locale. La protection de saved eip est laisse au canari introduit par stack-protector.
    Ces deux fonctionnalites permettent de specifier la taille du tableau a proteger, donc doivent parser le code/IL avant compilation.

    Citation Envoyé par Aspic Voir le message
    afin de détecter d'éventuels buffer overflow/underflow sur des buffers statiques (je sais qu'il existe des outils pour cela mais je voudrais comprendre par moi même et me créer mon propre outil).
    Pour cppcheck, c'est de l'analyse statique, donc c'est facile.
    Pour avoir une solution de protection au runtime, il faut introduire un hook au niveau de la pre-compilation.

    Bon courage.

  6. #6
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Tout d'abord, merci pour vos réponses.
    Donc en gros au runtime, tu ne peux pas savoir en examinent simplement la stack quelle est la taille de ton tableau. Tu as seulement la taille totale occupee par les variables locales.
    Par curiosité, comment peut-on récupérer en C la taille totale des variables allouées sur la stack ? Qui sait, cela pourra peut être me servir pour détecter un éventuel dépassement de stack.


    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
     
    #define sprintf(buf, ....) sprintf_check((buf), ....)
     
    int sprintf_check(char* buf, ....)
    {
        // Je peux intercepter l'appel à cette fonction mais comment vérifier ce type d'overflow ?
        // Je peux avoir son adresse mais pas la taille réelle car sizeof ne fonctionne pas, il me donnera la taille du pointeur...
        printf("0x%p\n", buf);
     
    }
     
    void foo(char* buf)
    {
        sprintf(buf, "%s", "je vais faire un overflow !!");
    }
     
    int main()
    {
        char b[2];
        foo(b);
    }
    Ok donc dans ce cas, y'a t-il un moyen de détecter ce genre d'overflow ? Puisqu'il est impossible de connaitre la vraie taille du buffer dans la fonction foo, comment faire ?

    PS : Je suis sur que Cppcheck ne peut pas vérifier ce genre de problème avec une simple analyse statique.
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  7. #7
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Par défaut
    Citation Envoyé par Aspic Voir le message
    Par curiosité, comment peut-on récupérer en C la taille totale des variables allouées sur la stack ? Qui sait, cela pourra peut être me servir pour détecter un éventuel dépassement de stack.
    Je peux parler que de Linux ici, avec gcc et convention cdecl. Tu peux inliner de l'asm. Pour 32 bits, si tu fais un truc du genre:
    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    push eax
    pushfd
    mov eax, ebp
    sub eax, esp    ; ici eax contient vaguement la taille de ta stack frame
    popfd
    pop eax

    Tu as une taille approximative:
    1. Alignee sur 4 bytes ou 8 bytes (32/64 bits), donc du padding compilo
    2. Dependant de la sauvegarde des registres en prologue de fonction. Si tu as un pushad, tu decales ta stack d'autant


    Citation Envoyé par Aspic Voir le message
    Ok donc dans ce cas, y'a t-il un moyen de détecter ce genre d'overflow ? Puisqu'il est impossible de connaitre la vraie taille du buffer dans la fonction foo, comment faire ?
    Bah tu peux pas a ma connaissance. C'est pour ca que les protections se font a la compilation, ou en imposant l'utilisant des fonctions consideres safes (snprintf, ...).

    Citation Envoyé par Aspic Voir le message
    PS : Je suis sur que Cppcheck ne peut pas vérifier ce genre de problème avec une simple analyse statique.
    Pourquoi? Toutes les tailles sont connues ici: b => 2 bytes, cste "je vais faire un overflow !!" => 28 bytes. C'est assez simple pour analyseur statique de trouver ce genre de probleme dans des cas simples comme ca.

Discussions similaires

  1. Réponses: 5
    Dernier message: 12/12/2013, 11h43
  2. Passer l'adresse d'un tableau statique
    Par Fooshi dans le forum C
    Réponses: 13
    Dernier message: 13/08/2010, 17h25
  3. Réponses: 5
    Dernier message: 02/05/2009, 15h27
  4. taille tableau statique
    Par Rniamo dans le forum C++
    Réponses: 14
    Dernier message: 14/06/2008, 16h16
  5. qbasic : taille d'un tableau
    Par clood200 dans le forum Basic
    Réponses: 2
    Dernier message: 16/09/2003, 07h26

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