OVH Cloud OVH Cloud

Question sur malloc - OpenBSD

16 réponses
Avatar
ja
Je suis en train de lire par curiosit=E9 cette page de man OpenBSD sur mall=
oc et je tombe sur cette phrase :=20

http://www.openbsd.org/cgi-bin/man.cgi?query=3Dmalloc&sektion=3D3

When using malloc() be careful to avoid the following idiom:

if ((p =3D malloc(num * size)) =3D=3D NULL)
err(1, "malloc");

Pourquoi ne pas utiliser ce test =3D=3D NULL ?

Cordialement

6 réponses

1 2
Avatar
espie
In article ,
ja wrote:
En fait en lisant qques livres (peut être trop scolaire) j'ai souvent vu
que les auteurs conseillaient de déclarer un pointeur puis de
l'initialiser à NULL afin de ne pas oublier de l’allouer plus tard dans
le code.

Voici deux exemples :

Figure 2.4
http://books.google.fr/books?id=jfn1IAN3dvwC&pg=PT67&lpg=PP1&dq=secure+programming+c&hl=fr du livre "Secure Coding in C and C++"

p337 du livre "Programmation système en C sous Linux" :
http://books.google.fr/books?idçtyMAntgaAC&pg=PA337&dq=malloc+null&hl=fr&sa=X&ei=tQLpUfr8NsnMOM_TgPAK&ved DcQuwUwAA#v=onepage&q=malloc%20null&fúlse


Après, peut être que c'est inutile ? peut être que le compilateur init à
0 par défaut ?


Non, uniquement pour les variables statiques.


Initialiser les variables a une valeur decente par defaut n'est utile
QUE dans certaines conditions.

Dans
{
char *s;

...

s = malloc(qqc);
if (s == NULL) {
...
}
...
}

tu n'as pas besoin d'initialiser s a 0, tout betement parce que ton compilo
est parfaitement capable de te dire si s a ete utilisee sans avoir ete
initialisee.


Apres, si tu es C99 ou plus, un style raisonnable consiste a ne declarer
les variables QUE au moment ou on va les initialiser. Le code precedent
devient
{
char *s = malloc(qqc);
if (s == NULL) {
...
}
...
}

ca ne s'applique pas au noyau d'Open (on a encore une archi sur laquelle
le seul compilo supporte est gcc 2.95... un compilo plus recent fait des
trucs invraisemblablement faux en termes d'optimisation).

(note que ce style est sujet a controverse pour les vieux, qui veulent
absolument declarer toutes les variables en tete de fonction)


Désolé, kern_sysctl.c était effectivement pas un très bon exemple.



Visiblement, tu es relativement debutant. Attaquer par le code d'un
noyau n'est pas du tout du tout un bon exemple.

Je te recommande de commencer par apprendre un peu le langage pour de vrai,
par exemple avec le K&R, avant de t'attaquer a des trucs plus complexes.


Cote "securite", de tels conseils sont relativement nocifs.
Les initialisations parasites peuvent donner l'illusion que le code
est propre, alors que des problemes plus sournois s'y cachent.
Pire: les initialisations en plus rajoutent "du bruit" en terme de code
qui au final ne sert pas (parce que ton compilo va bien evidemment
optimiser une double initialisation), et conduisent certaines personnes
a encapsuler leurs allocations dans des grosses macros qui font plein
de trucs et qui cassent tout.

La bonne securite s'obtient generalement en sachant ce qu'on fait, donc
commence par reellement apprendre le langage depuis les bases, puis en
essayant d'ecrire du code le plus clair possible, en evitant d'etre
"cute"...

Le code noyau, pour apprendre a ecrire du code C, c'est pas tip-top. Bon,
tu aurais pu faire pire et regarder le code noyau linux (qui est tellement
noye dans les spinlocks que plus rien n'est visible) ou le code GNU (qui
n'est a peu pres jamais ecrit en C sans au moins trois surcouches de
macros et d'indirections a la con)
Avatar
JKB
Le Fri, 19 Jul 2013 10:09:09 +0000 (UTC),
Marc Espie écrivait :
In article ,
ja wrote:
En fait en lisant qques livres (peut être trop scolaire) j'ai souvent vu
que les auteurs conseillaient de déclarer un pointeur puis de
l'initialiser à NULL afin de ne pas oublier de l’allouer plus tard dans
le code.

Voici deux exemples :

Figure 2.4
http://books.google.fr/books?id=jfn1IAN3dvwC&pg=PT67&lpg=PP1&dq=secure+programming+c&hl=fr du livre "Secure Coding in C and C++"

p337 du livre "Programmation système en C sous Linux" :
http://books.google.fr/books?idçtyMAntgaAC&pg=PA337&dq=malloc+null&hl=fr&sa=X&ei=tQLpUfr8NsnMOM_TgPAK&ved DcQuwUwAA#v=onepage&q=malloc%20null&fúlse




Après, peut être que c'est inutile ? peut être que le compilateur init à
0 par défaut ?


Non, uniquement pour les variables statiques.



C'est vrai, ça ? J'ai des souvenirs où les variables statiques ne
sont pas initialisées par défaut sauf à le faire explicitement.

Initialiser les variables a une valeur decente par defaut n'est utile
QUE dans certaines conditions.

Dans
{
char *s;

...

s = malloc(qqc);
if (s == NULL) {
...
}
...
}

tu n'as pas besoin d'initialiser s a 0, tout betement parce que ton compilo
est parfaitement capable de te dire si s a ete utilisee sans avoir ete
initialisee.


Apres, si tu es C99 ou plus, un style raisonnable consiste a ne declarer
les variables QUE au moment ou on va les initialiser. Le code precedent
devient
{
char *s = malloc(qqc);
if (s == NULL) {
...
}
...
}

ca ne s'applique pas au noyau d'Open (on a encore une archi sur laquelle
le seul compilo supporte est gcc 2.95... un compilo plus recent fait des
trucs invraisemblablement faux en termes d'optimisation).



Des noms, des noms, des noms !

(note que ce style est sujet a controverse pour les vieux, qui veulent
absolument declarer toutes les variables en tete de fonction)



Je dois être un vieux capable de programmer en fortran dans
n'importe quel langage...

Désolé, kern_sysctl.c était effectivement pas un très bon exemple.



Visiblement, tu es relativement debutant. Attaquer par le code d'un
noyau n'est pas du tout du tout un bon exemple.

Je te recommande de commencer par apprendre un peu le langage pour de vrai,
par exemple avec le K&R, avant de t'attaquer a des trucs plus complexes.




K&R _ansi_, je suppose que tu ne parlais pas de l'édition
originelle. Parce que si on rentre dans les subtilités des passages
d'arguments du C K&R, je pense que l'OP n'en a pas fini.

Cote "securite", de tels conseils sont relativement nocifs.
Les initialisations parasites peuvent donner l'illusion que le code
est propre, alors que des problemes plus sournois s'y cachent.
Pire: les initialisations en plus rajoutent "du bruit" en terme de code
qui au final ne sert pas (parce que ton compilo va bien evidemment
optimiser une double initialisation), et conduisent certaines personnes
a encapsuler leurs allocations dans des grosses macros qui font plein
de trucs et qui cassent tout.

La bonne securite s'obtient generalement en sachant ce qu'on fait, donc
commence par reellement apprendre le langage depuis les bases, puis en
essayant d'ecrire du code le plus clair possible, en evitant d'etre
"cute"...

Le code noyau, pour apprendre a ecrire du code C, c'est pas tip-top. Bon,
tu aurais pu faire pire et regarder le code noyau linux (qui est tellement
noye dans les spinlocks que plus rien n'est visible) ou le code GNU (qui
n'est a peu pres jamais ecrit en C sans au moins trois surcouches de
macros et d'indirections a la con)



Je sens le troll arriver. Il est vrai qu'on est trolldi. Donc je
marche dedans en disant qu'il aurait pu mieux faire et regarder le
code noyau de NetBSD ;-)

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
espie
In article ,
JKB wrote:
K&R _ansi_, je suppose que tu ne parlais pas de l'édition
originelle. Parce que si on rentre dans les subtilités des passages
d'arguments du C K&R, je pense que l'OP n'en a pas fini.



Oui, bien sur. Dans ma tete le C pre-ANSI est finalement mort.

Je sens le troll arriver. Il est vrai qu'on est trolldi. Donc je
marche dedans en disant qu'il aurait pu mieux faire et regarder le
code noyau de NetBSD ;-)



Ah, Trolldi...
NetBSD, le systeme qui cross-compile tout au point que certains bouts
d'architecture sont totalement casses (confere la libm sur vax, avec
le code d'atan2f betement recopie de sinf, donc qui ne risque pas trop
de marcher vu qu'il y a un parametre de plus...)


Plus serieusement, le code noyau n'est jamais du C standard, comme tout
code embarque qui se respecte.

C'est a peu pres le pire qu'on puisse imaginer pour apprendre le langage.
Vu les questions du posteurs de depart, il faudrait deja qu'il apprenne
a lire des paragraphes entiers, ou a preter un peu d'attention aux details
comme remarquer que le malloc() qu'il voit a 2 parametres de trop.

Il y a deja des trucs sournois dans du code userland, mais sur du code noyau,
entre les specificites de l'edition de liens (les variables ne sont pas
forcement initialisees comme en userland), les specificites du processeur
(cf les bugs de longsoon et des problemes de pipeline qui font que certaines
gardes anti pointeur nul peuvent finir en panic), j'en passe et des
meilleures, c'est pas avec ca qu'il va arriver a faire quelque chose d'a peu
pres rigoureux avec un langage qui, soyons franc, est hostile pour le
debutant.

(sans compter donc les trucs evidents a voir comme le fait qu'un noyau
est compile en free-standing, et donc que les fonctions-de-la-libc ne sont
pas les fonctions-de-la-libc-du-noyau, entre printf qui prend des chaines
de formats subtilement differentes, malloc qui n'a rien a voir, la gestion
memoire qui est tres differente, la possibilite de faire des trucs
totalement non portables avec les adresses memoires, les problemes d'endianess
qui pointent leur nez des qu'on met une carte graphique dans autre chose
qu'un intel, etc, etc)
Avatar
JKB
Le Fri, 19 Jul 2013 10:26:30 +0000 (UTC),
Marc Espie écrivait :
In article ,
JKB wrote:
K&R _ansi_, je suppose que tu ne parlais pas de l'édition
originelle. Parce que si on rentre dans les subtilités des passages
d'arguments du C K&R, je pense que l'OP n'en a pas fini.



Oui, bien sur. Dans ma tete le C pre-ANSI est finalement mort.

Je sens le troll arriver. Il est vrai qu'on est trolldi. Donc je
marche dedans en disant qu'il aurait pu mieux faire et regarder le
code noyau de NetBSD ;-)



Ah, Trolldi...
NetBSD, le systeme qui cross-compile tout au point que certains bouts
d'architecture sont totalement casses (confere la libm sur vax, avec
le code d'atan2f betement recopie de sinf, donc qui ne risque pas trop
de marcher vu qu'il y a un parametre de plus...)



Alors tu vas me permettre de parler d'OpenBSD qui est cassé sur
Loongson et des locales assez mal supportées sur sparc/sparc64.
C'est tout de même plus récent et plus utilisé qu'un VAX sous
NetBSD.

Plus serieusement, le code noyau n'est jamais du C standard, comme tout
code embarque qui se respecte.

C'est a peu pres le pire qu'on puisse imaginer pour apprendre le langage.
Vu les questions du posteurs de depart, il faudrait deja qu'il apprenne
a lire des paragraphes entiers, ou a preter un peu d'attention aux details
comme remarquer que le malloc() qu'il voit a 2 parametres de trop.



Et encore, il a raté l'overcommit sur certains systèmes :-D (oui, on
est encore trolldi).

Il y a deja des trucs sournois dans du code userland, mais sur du code noyau,
entre les specificites de l'edition de liens (les variables ne sont pas
forcement initialisees comme en userland), les specificites du processeur
(cf les bugs de longsoon et des problemes de pipeline qui font que certaines
gardes anti pointeur nul peuvent finir en panic), j'en passe et des
meilleures, c'est pas avec ca qu'il va arriver a faire quelque chose d'a peu
pres rigoureux avec un langage qui, soyons franc, est hostile pour le
debutant.



Pas que pour le débutant. Si tu voyais le code qui me passe entre
les pattes... Quant à gcc, si certains jours je tenais les
développeurs de gcc sous la main, ils passeraient un sale
quart-d'heure (cf les changement d'allocation des pointeurs
statistiques dans gcc 4.7 qui a fichu L4Ka par terre).

(sans compter donc les trucs evidents a voir comme le fait qu'un noyau
est compile en free-standing, et donc que les fonctions-de-la-libc ne sont
pas les fonctions-de-la-libc-du-noyau, entre printf qui prend des chaines
de formats subtilement differentes, malloc qui n'a rien a voir, la gestion
memoire qui est tres differente, la possibilite de faire des trucs
totalement non portables avec les adresses memoires, les problemes d'endianess
qui pointent leur nez des qu'on met une carte graphique dans autre chose
qu'un intel, etc, etc)



Merci, je sais... D'ailleurs, j'ai un truc pour NetBSD/sparc64 sur
le feu...

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
jca
JKB writes:

Le Fri, 19 Jul 2013 10:26:30 +0000 (UTC),
Marc Espie écrivait :
In article ,
JKB wrote:
K&R _ansi_, je suppose que tu ne parlais pas de l'édition
originelle. Parce que si on rentre dans les subtilités des passages
d'arguments du C K&R, je pense que l'OP n'en a pas fini.



Oui, bien sur. Dans ma tete le C pre-ANSI est finalement mort.

Je sens le troll arriver. Il est vrai qu'on est trolldi. Donc je
marche dedans en disant qu'il aurait pu mieux faire et regarder le
code noyau de NetBSD ;-)



Ah, Trolldi...
NetBSD, le systeme qui cross-compile tout au point que certains bouts
d'architecture sont totalement casses (confere la libm sur vax, avec
le code d'atan2f betement recopie de sinf, donc qui ne risque pas trop
de marcher vu qu'il y a un parametre de plus...)



Alors tu vas me permettre de parler d'OpenBSD qui est cassé sur
Loongson et des locales assez mal supportées sur sparc/sparc64.
C'est tout de même plus récent et plus utilisé qu'un VAX sous
NetBSD.



Histoire de rendre trolldi un peu plus utile que de moyenne, j'aimerais
savoir qu'est-ce qui est cassé sur Loongson et en quoi les locales sont
encore plus mal supportées sur sparc que sur d'autres archs. Pourrais- tu
développer sur un autre forum plus approprié / me contacter par m ail ?

[...]

--
Jérémie Courrèges-Anglas
Empreinte PGP : 61DB D9A0 00A4 67CF 2A90 8961 6191 8FBF 06A1 1494
Avatar
Antoine Leca
ja écrivit :
En fait en lisant qques livres (peut être trop scolaire) j'ai souvent
vu que les auteurs conseillaient de déclarer un pointeur puis de
l'initialiser à NULL



Mmmm... pas sûr de bien suivre...
D'abord, en C, il n'y a pas de choix : il faut déclarer le pointeur ; ce
n'est pas un conseil, c'est obligatoire. La seule chose où on peut
tergiverser, c'est sur l'initialisation à NULL. Qui comme tu le
remarques plus bas, est déjà faite pour les variables statiques.

Si on parle de déclaration de variable locales (auto), il peut être
utile de les initialiser explicitement si le code ne le fait pas
naturellement, pour éviter les valeurs aléatoires d'initialisations qui
ont des effets aléatoires en cas de bogues et c'est pénible ; mais il
n'y a rien de spécifique aux pointeurs ; et pour le coup NULL est ÀMHO
une valeur sous-optimale, un truc spécifique genre 0xCAFE ou 0xD0BE
rendra le même service (faire péter) mais donnera en plus une indication
sur la provenance.

afin de ne pas oublier de l’allouer plus tard dans le code.



Les compilos modernes sont gentils, si tu déclares une variable mais ne
l'initialises pas ou ne l'utilises pas, ils te le signalent...


Antoine
1 2