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 :

vérifier la taille d'un tableau de char passé en paramètre


Sujet :

C

  1. #1
    Membre confirmé Avatar de zentaf
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut vérifier la taille d'un tableau de char passé en paramètre
    Bonjour,

    J'ai une fonction en C, que son utilisateur doit lui passer un tableau vide de 16 char.
    La fonction fait un ensemble de traitement et en dernier copie le résultat qui fait 16 char dans le tableau passé en paramètre avec strcpy().

    Du coup, je veux, au sein de ma fonction, vérifier la taille du tableau que l'utilisateur passe à ma fonction, pour retourner une erreur en cas d'une taille insuffisante qui peut causer un débordement de tampon.

    Merci,
    Shan.

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Réponse simple : tu ne peux pas, ce n'est pas possible en C.

    Il va falloir trouver un autre moyen
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Ta fonction est-elle ainsi définie : Type ma_fonction(char reponse[16] ?

    Si oui, sache que le 16 est purement indicatif et qu'un tableau de n'importe quelle taille sera accepté. Cette déclaration est en fait équivalente à : Type ma_fonction(char *reponse).

    Si ton compilateur est gentil et que tu as activé les bonnes options, tu auras peut-être un warning.

  4. #4
    Membre confirmé Avatar de zentaf
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Citation Envoyé par ram-0000 Voir le message
    Réponse simple : tu ne peux pas, ce n'est pas possible en C.

    Il va falloir trouver un autre moyen
    Comme par exemple ?

  5. #5
    Membre confirmé Avatar de zentaf
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Ta fonction est-elle ainsi définie : Type ma_fonction(char reponse[16] ?

    Si oui, sache que le 16 est purement indicatif et qu'un tableau de n'importe quelle taille sera accepté. Cette déclaration est en fait équivalente à : Type ma_fonction(char *reponse).

    Si ton compilateur est gentil et que tu as activé les bonnes options, tu auras peut-être un warning.
    justement le prototype de ma fonction est comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type ma_fonction(char *reponse)

  6. #6
    Membre émérite Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Par défaut
    Citation Envoyé par zentaf Voir le message
    Comme par exemple ?
    Il suffit de passer la taille en paramètre....

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    @crocodilex : passer la taille en paramètre ne garanti rien du tout une fois à l'intérieur de la fonction !

    @ zentaf : OK, c'était au cas où

    Dans un cas comme ça, tu as deux possibilités :
    • tu alloues toi même le tableau, ça t'oblige à changer le prototype de ta fonction et la libération se fera hors de cette fonction
    • tu assumes que le tableau à la bonne taille, c'est à l'appelant de faire les vérifications

  8. #8
    Membre émérite Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Par défaut
    Citation Envoyé par Bktero Voir le message
    @crocodilex : passer la taille en paramètre ne garanti rien du tout une fois à l'intérieur de la fonction !
    Si l'utilisateur passe n'importe quoi en paramètre, forcément il court au désastre.
    Mais en règle générale, c'est comme ça que l'on procède. Il suffit de prendre pour exemple la libc (ex: beaucoup de fonctions de manipulations de mémoire sont basées sur ce principe)

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Non, une bonne partie des fonctions de la bibliothèque standard donne un paramètre une taille annoncée, comme memcpy() mais ces fonctions assument que la zone mémoire est correctement allouée. Cela ne constitue pas une vérification sur la taille réellement allouée. Tu peux passer une taille 100 alors que la taille réellement allouée est de 10 avec memcpy() hein

    Si l'utilisateur passe n'importe quoi en paramètre, forcément il court au désastre.
    Ça reste une des grandes problématique de la programmation défensive : ne pas faire confiance à ce qui est passé en paramètres et toujours faire en sorte que même si c'est du garbage en entrée (souvent, on tente alors que le fonctionnement soit assuré et on renverra une valeur bidon mais sans planter).

  10. #10
    Membre émérite Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Par défaut
    OK, tout à fait d’accord.
    Ma remarque était de dire qu’il suffit simplement de passer la taille en paramètre, comme le font les fonctions de la libc. Certes, les fonctions de la libc ne font pas de vérification sur la quantité de mémoire allouée (et d’ailleurs je ne vois pas comment elles pourraient). Mais pour répondre aux exigences de notre PO, le paramètre «taille» est une solution pour résoudre son problème : «Dis-moi quelle quantité de mémoire tu as alloué, et je te dirais si c’est suffisant ou non.»

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Type ma_fonction(char *reponse, size_t taille) {
    	if (taille < 16) {
    		[...]
    		return PAS_ASSEZ_DE MEMOIRE;
    	}
    	[...]
    }

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 96
    Par défaut
    Si c'est un tableau de taille raisonnable tu peux prendre les x premiers éléments du tableau passé en paramètre et les mettre dans un tableau local à ta fonction. Tu maitriseras donc la taille.

    C'est pas très beau mais c'est une solution...

    Ca marche si le tableau passé en paramètre est trop grand par contre s'il est trop petit... ben c'est pas la bonne solution.

  12. #12
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2013
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 33
    Par défaut
    Salut !

    Un assert peut également faire l'affaire, mais ce n'est pas très idéal.
    Tu peux aussi dans ton type Type rajouter une variable / énumération pour voir si c'est une erreur

  13. #13
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par AceSir Voir le message
    Un assert peut également faire l'affaire, mais ce n'est pas très idéal.
    Tu peux aussi dans ton type Type rajouter une variable / énumération pour voir si c'est une erreur
    Je ne vois pas en quoi un assert permettrait de résoudre ce problème !

    De même une valeur de retour spécifique permettrait de remonter l'erreur une fois celle-ci détectée mais n'aide absolument pas à la détecter.

  14. #14
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par stephane.combes Voir le message
    Si c'est un tableau de taille raisonnable tu peux prendre les x premiers éléments du tableau passé en paramètre et les mettre dans un tableau local à ta fonction. Tu maitriseras donc la taille.

    C'est pas très beau mais c'est une solution...

    Ca marche si le tableau passé en paramètre est trop grand par contre s'il est trop petit... ben c'est pas la bonne solution.
    Et une fois traitée, comment remontes-tu les données à la fonction appelante ?


    Citation Envoyé par AceSir Voir le message
    Salut !

    Un assert peut également faire l'affaire, mais ce n'est pas très idéal.
    Tu peux aussi dans ton type Type rajouter une variable / énumération pour voir si c'est une erreur
    Assert..... Mmmm.... On en met en général pour les cas non prévus et non gérés et aussi non gérables. Mais un assert sur quoi ? Sur la taille réellement allouée qu'on ne connait pas ?


    Faire une fonction telle que Type f(char * tab, size_t taille) ne sert à rien puisqu'on peut l'appeler comme ça : char c; f(&c, 16);.
    De plus, la taille est fixe, ce n'est même pas comme le mec pouvait se dire "aller, j'essayer de mettre 15 ou 17 pour voir si ça suffit". Non ! c'est toujours 16. Pour moi, cela doit faire parti des commentaires au dessus de la méthode (taille attendue = 16) et pourquoi d'appeler le paramètre formel avec un nom explicite (eg 16char_pointer).


    AceSir suggère une solution potentiellement correte (qui pourrait se révéler moche visuellement dans le code, à voir) qui est de créer un nouveau type. On pourrait avoir typedef data16 char[16] et ensuite de caster le pointeur en char* pour l'interpréter comme tel. Ce cast pourrait se cacher derrière des macros ou des fonctions pour une utilisation plus aisée.


    Pour moi, la seule vraie solution est d'allouer la mémoire dans la fonction et de renvoyer le pointeur. Ainsi, on s'assure de la taille réellement allouée. L'appelant devra libérer cette mémoire quand il n'en aura plus besoin. Le risque de cette solution est une fuite mémoire ; risque à mettre en regard avec celui de segmentation fault ou de pointeur jardinier des méthodes où on suppose que la mémoire réellement allouée est au moins de 16 octets.

  15. #15
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Bonjour,

    La seule solution vraiment defensive est la suivante :

    Citation Envoyé par Bktero Voir le message
    Pour moi, la seule vraie solution est d'allouer la mémoire dans la fonction et de renvoyer le pointeur. Ainsi, on s'assure de la taille réellement allouée.
    Le probleme etant :
    Citation Envoyé par Bktero Voir le message
    L'appelant devra libérer cette mémoire quand il n'en aura plus besoin.
    La seule autre solution propre, mais qui ne garantie rien, est de passer un pointeur alloue ET sa taille, et de supposer que la taille reellement allouee est au moins egale a la taille passee en argument.

    Dans les deux cas, l'appelant peut faire une bourde : fuite memoire dans le premier cas, jardinage (labourage ?) de la memoire dans le second.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Citation Envoyé par Bktero Voir le message
    AceSir suggère une solution potentiellement correte (qui pourrait se révéler moche visuellement dans le code, à voir) qui est de créer un nouveau type. On pourrait avoir typedef data16 char[16] et ensuite de caster le pointeur en char* pour l'interpréter comme tel. Ce cast pourrait se cacher derrière des macros ou des fonctions pour une utilisation plus aisée.
    Oh, ça me donne une idée: Avec ou sans typedef, on doit pouvoir faire ceci pour forcer la taille:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void maFonction(char (*tab)[16]) {}
     
    int main(void)
    {
    	char toto[16];
    	char tata[42];
    	maFonction(&toto);
    	maFonction(&tata); /*Donne au moins un warning sous Visual et GCC*/
    	return 0;
    }
    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.

  17. #17
    Membre Expert Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Par défaut
    Citation Envoyé par Bktero
    Citation Envoyé par stephane.combes
    Si c'est un tableau de taille raisonnable tu peux prendre les x premiers éléments du tableau passé en paramètre et les mettre dans un tableau local à ta fonction. Tu maitriseras donc la taille.

    C'est pas très beau mais c'est une solution...

    Ca marche si le tableau passé en paramètre est trop grand par contre s'il est trop petit... ben c'est pas la bonne solution.
    Et une fois traitée, comment remontes-tu les données à la fonction appelante ?
    Tout à fait d'accord avec Bktero. Cette façon de faire a même un nom : c'est de la procrastination !

  18. #18
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2013
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 33
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Assert..... Mmmm.... On en met en général pour les cas non prévus et non gérés et aussi non gérables. Mais un assert sur quoi ? Sur la taille réellement allouée qu'on ne connait pas ?
    Et bien sur la taille du tableau. Mais cela implique de la passer en paramètre... Donc au final, on peut faire mieux, je le reconnais.

    Citation Envoyé par gl
    Je ne vois pas en quoi un assert permettrait de résoudre ce problème !
    Si je ne m'abuse zentaf veut vérifier si l'utilisateur passe un tableau d'une taille correcte à sa fonction. Un assert plante le programme si ce n'est pas le cas. Alors certes ce n'est pas propre du tout, et ce n'est pas franchement une bonne idée, mais c'est une solution envisageable.

    Mais je pense qu'on est tous d'accord qu'il vaut mieux allouer le tableau dans la fonction et retourner un pointeur

  19. #19
    Membre chevronné Avatar de I_believe_in_code
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 219
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Oh, ça me donne une idée: Avec ou sans typedef, on doit pouvoir faire ceci pour forcer la taille:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void maFonction(char (*tab)[16]) {}
     
    int main(void)
    {
    	char toto[16];
    	char tata[42];
    	maFonction(&toto);
    	maFonction(&tata); /*Donne au moins un warning sous Visual et GCC*/
    	return 0;
    }
    mais maFonction ne peut toujours pas vérifier que la taille allouée est bien suffisante.

    Méthode rouleau-compresseur :
    créer un type abstrait de donnée "Tableau" (tableau de char si vous voulez) dont les "accesseurs" vérifient systématiquement les "bornes".

    Ces tableaux peuvent éventuellement être redimensionnables en cas de besoin.

  20. #20
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par AceSir Voir le message
    Un assert plante le programme si ce n'est pas le cas. Alors certes ce n'est pas propre du tout, et ce n'est pas franchement une bonne idée, mais c'est une solution envisageable.
    Un assert arrête brutalement le programme si une condition n'est pas vérifiée. Mais dans le cas présent, le problème est justement d'avoir une condition permettant de vérifier la taille du tableau. Et que l'on utilise assert ou autre chose, le souci reste le même.

    Citation Envoyé par AceSir Voir le message
    Mais je pense qu'on est tous d'accord qu'il vaut mieux allouer le tableau dans la fonction et retourner un pointeur
    Pas nécessairement, il y a plusieurs stratégies (allouer soi même, ne rien vérifier, demander la taille du tableau en paramètre, créer un type dédié, créer un type "tableau" gérant sa taille, etc.), après c'est une histoire de contexte et de compromis.

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/01/2015, 14h24
  2. Réponses: 6
    Dernier message: 07/02/2011, 09h06
  3. Vérifier dernier caractere d'un tableau de char
    Par Kpone dans le forum Débuter
    Réponses: 3
    Dernier message: 31/12/2008, 14h22
  4. Tableau de char[] passé dans une fonction
    Par Joratois dans le forum C
    Réponses: 26
    Dernier message: 07/06/2007, 15h06
  5. Réponses: 3
    Dernier message: 01/02/2006, 21h31

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