Bonjour,
J'ai ce petit code ou je déclare deux pointeurs tableau je veux savoir si juste la déclaration et l'affectation peut donner le mauvais accès à la mémoire réservée par ce pointeur ou c'est après la mauvaise utilisation de malloc qui peut causer le vol de données ou l'injection de mauvaise données.
Mon code C:
void mafonction(int* tab1, int* tab2, int len)
{
int i;
for(i = 0; i < len; i++)
tab1[i] = tab2[i] ;
}
Merci d'avance.
# Pointeur
Posté par max22 . Évalué à 1.
Ton code est l'implémentation de la fonction memcpy de la librairie standard du C. Elle ne contient pas d'erreur.
C'est au développeur qui va l'utiliser de faire attention à ne pas faire de conneries en utilisant cette fonction. Il doit allouer correctement la mémoire, et passer le bon paramètre "len" sinon effectivement ça peut poser des problèmes de sécurité.
[^] # Re: Pointeur
Posté par Cyril Brulebois (site web personnel) . Évalué à 2.
Attention à son emploi cependant. Citons la page de manuel
memcpy(3)
:Debian Consultant @ DEBAMAX
# 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 3. Dernière modification le 08 novembre 2019 à 18:17.
un pointeur en soi ne réserve pas de mémoire :
Ici aucune mémoire n'a été allouée aux pointeurs
input
etoutput
donc l'appel àmafonction
va déréférencer un pointeurNULL
ce qui va engendrer un comportement non-défini, ce qui est à-peu-près passible de la peine capitale pour un programmeur C.(Là je suis sympa, il me semble que Linux est pas trop méchant et plante le programme direct quand le pointeur est
NULL
, par contre si le pointeur n'avait pas été initialisé du tout, c'était des feux d'artifice)Tu peux décider d'utiliser de la mémoire sur la pile pour appeler ta fonction:
Ici, on a bien de la mémoire pour l'input et l'output (mémoire de la pile), mais l'appel à
mafonction
va engendrer la lecture du tableauinput
qui n'a pas été initialisé, ce qui va provoquer un comportement non-défini, ce qui est à-peu-près passible de la peine capitale pour un programmeur C.Tu peux corriger en initialisant les données lues :
Là, c'est bien on a initialisé les données, mais on a dépassé la taille du tableau
input
, et on commence à lire et à écrire des données en débordant du tableau , ce qui va provoquer un comportement non-défini, ce qui est à-peu-près passible de la peine capitale pour un programmeur C.On peut s'en sortir en contraignant la taille de ton tableau de sortie.
Tu peux aussi décider d'allouer un tableau sur le tas et bien penser à initialiser les données et tout et tout.
Mais on aura oublié d'invoquer
free
afin de libérer la mémoire allouée pourinput
etoutput
, créant une fuite de mémoire qui est à-peu-près passible de la peine capitale pour un programmeur C.C'est le côté fun du C, on donne au programmeur une infinité d'opportunités de se prendre les pieds dans le tapis.
Bon 'dredi !
[^] # Re: 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 2.
le dernière exemple est faux,
output
devrait être un pointeur versint
pas juste unint
, mea maxima culpa.[^] # Re: 'pouvez répéter la questioooon ?
Posté par David Marec . Évalué à 3.
Ben non.
Vous pouvez lancer ce programme autant de fois que vous voulez sous Linux, sous Windows ou BSD, vous ne verrez pas la moindre fuite de mémoire.
Attention,
sizeof
est un opérateur, pas une fonction. Il ne devrait y avoir de parenthèses que si l'on cible un type et non une variable (unary-expression).[^] # Re: 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 3.
J'insiste, il y aura une fuite de mémoire à chaque exécution te ce programme, cette fuite sera résorbée par le système d'exploitation à chaque fin d'exécution, mais fuite de mémoire il y aura.
Une fuite de mémoire est caractérisée par l'incapacité du programme a libérer lui-même la mémoire qu'il a allouée. Dans l'exemple que je donne, une fois qu'on a quitté la fonction
main()
on perd l'adresse de la mémoire allouée, ce qui caractérise cette fuite. Je reconnais que l'exemple est un peu tordu dans le sens où, de toutes façons, on ne peut pas faire grand chose en C une fois que lemain()
est terminé, mais si le code dans lemain()
était dans une fonctionf()
qu'on appelait à la chaîne, peut-être serais-tu plus enclin à la voir.[^] # Re: 'pouvez répéter la questioooon ?
Posté par David Marec . Évalué à 3.
Vous essayez surtout de trouver une définition de la "fuite mémoire" qui vous donnerait raison.
On peut laisser traîner des choses comme des tubes nommés.
Attention, j'ai bien dit "Sous Linux etc.", ce n'est absolument pas le cas sur la plupart des OS dit "temps-réel" - surtout ceux qui tournent sur des archi sans MMU. -
T'inquiète, je sais ce qu'est une fuite mémoire, une vraie. J'ai vu des gens coder en Java.
[^] # Re: 'pouvez répéter la questioooon ?
Posté par David Marec . Évalué à 3.
Non, la valeur est «indeterminée», ce n'est pas un cas d'«undefined behavior».
[^] # Re: 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 1.
J'insiste, section A.6.2 Undefined behavior
Pour les modernes, c'est aussi valable en C++ (j'ai la flemme de sortir le draft pour 17, mais c'est pareil), 8.5 alinea 12
les exceptions en question sont des
char
s.[^] # Re: 'pouvez répéter la questioooon ?
Posté par David Marec . Évalué à 2.
Qui se réfère à ceci,
même formule en C11:
La "synthèse" liste ce cas, tout en faisant référence à des articles … où l'UB n'est pas indiquée.
Je ne connais aucun compilo qui s'autorise à invoquer un démon nasal dans ce cas, et où
dev/mem
ne fonctionnerait pas.[^] # Re: 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 1.
Je n'aime pas la façon dont le standard C89 est rédigé, mais je ne pense pas qu'A.6.2 soit une synthèse, mais plutôt une espèce de section spéciale UB (bien que UB soit mentionné à plein d'autres endroits)
Je ne prendrais pas ça à la légère, ce type d'UB a été défini avec beaucoup d'attention et si même les dernières version du standard C++ la gardent, c'est que les compilateurs en profitent pour faire des optimisations de code assez tordues. Donc, pas de démon nasal, mais un code qui risque d'être surprenant au moment où tu t'y attends le moins.
[^] # Re: 'pouvez répéter la questioooon ?
Posté par David Marec . Évalué à 2.
Justement dans C11, c'est rédigé différemment, lorsque l'on a affaire à un UB, c'est dit explicitement dans l'article concerné.
Ce n'est certes pas à prendre à la légère, le contenu des tableaux dépend du sens du vent. Mais c'est parfois voulu.
C'est le cas de la plupart, voire toutes, les UB déclarées sous GCC. Il se permet souvent de zapper tout le code qui contient une UB, mais jamais dans ce cas précis, c'est à dire avec un tableau.
Lorsque la variable peut-être collée dans un registre, il va se comporter différemment.
- mais je crois que la norme mentionne ce cas précis. -
[^] # Re: 'pouvez répéter la questioooon ?
Posté par nazcafan . Évalué à 1. Dernière modification le 09 novembre 2019 à 10:23.
Le standard C89 a 89 occurences (😃) de l'expression behavior is undefined, et ce tout au long du document, par exemple en 3.3.3.2 (Address and indirection operators) alinéa 2
Par ailleurs l'annexe A.6.2 du C89 (Portability Issues -> Undefined behavior) est aussi présente dans C11, elle a simplement été déplacée en J.2. Le paragraphe sur l'utilisation des variables automatiques dont la valeur est indéterminée, y est toujours présent.
Par contre, là où tu sembles avoir raison, c'est que l'annexe J est informative, pas normative : elle devrait permettre d'interpréter le standard mais n'a pas valeur de norme. Étrange quand même de garder ça pendant plus de 30 ans dans le document si c'est faux ou douteux (c'est dans le dernier draft de C18)
je pense que tu fais référence à 6.3.2.1, alinéa 2 :
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.