Journal Traduction | Doit-on vérifier le pointeur pour NULL avant d'appeler la fonction free ?

Posté par  . Licence CC By‑SA.
Étiquettes :
-7
24
avr.
2024

Sommaire

La réponse brève est non. Cependant, cette question apparaît régulièrement sur Reddit, Stack Overflow et d'autres sites web, il est temps d'aborder le sujet. Il y a beaucoup de choses prenantes à réfléchir.

Titre de l'image

Remarque

Bonjour! Cet article a été initialement publié sur le website PVS-Studio écrit par Andrey Karpov.
J'ai traduit cet article théorique spécialement pour la communauté française. Bouquine bien !

Fonction free

La fonction free est déclarée dans le fichier d'en-tête <stdlib.h> comme suit :

void free( void *ptr );

La fonction libère la mémoire tampon avant alloué avec les fonctions malloc, calloc, realloc et aligned_alloc.

Si ptr est un pointeur NULL, la fonction ne fait rien.

Il n'est donc pas vérifier le pointeur avant d'appeler free.

if (ptr)     // une vérification redondante
  free(ptr);

Ce code est obsolète, car la vérification n'est d'aucune utilité. Si le pointeur est NULL, on peut le passer à la fonction free en toute sécurité. Les développeurs de la norme du C délibérément choisi cette solution :

cppreference.com : free

La fonction accepte (et ne fait rien avec) le pointeur null afin de réduire le nombre de cas particuliers.

Si le pointeur est non NULL, mais toujours invalide, la vérification ne protège de rien. Un pointeur non NULL invalide est toujours passé à la fonction free, ce qui cause un comportement indéfini.

cppreference.com : free

Le comportement est indéfini si la valeur de ptr n'est pas égale à une valeur renvoyée précédemment par malloc(), calloc(), realloc(), ou aligned_alloc() (depuis C11).

En outre, le comportement est indéfini si la zone de mémoire désigné par ptr a déjà été libérée, c'est-à-dire, free(), free_sized(), free_aligned_sized(), ou realloc() a déjà été appelée avec comme argument ptr et aucun appel à malloc(), calloc(), realloc(), ou aligned_alloc() abouti à un pointeur égal à ptr après.

Par conséquent, on peut et on doit écrire simplement :

free(ptr);

D'où viennent les questions de la vérification préliminaire des pointeurs ?

La documentation de la fonction free indique explicitement qu'on peut lui passer un pointeur NULL et qu'il ne pose aucun risque. Cependant, les discussions sur ce sujet continuent d'apparaître sur différents sites web. Les questions se divisent en deux catégories.

Les questions des développeurs débutants. Ce type de questions est le plus courant. C'est simple : les gens commencent à apprendre la programmation, ne sont pas conscientes quand il faut vérifier un pointeur et quand il ne faut pas le faire. Pour les jeunes développeurs, une simple explication suffit. Lorsque vous allouez de la mémoire avec malloc, vérifiez le pointeur. (P.S. Commentaire du traducteur : malheureusement, je n'ai pas encore traduit cet article, mais une traduction est à venir :) )
Sinon, le déréférencement d'un pointeur NULL peut causer un comportement indéfini. Avant de libérer la mémoire (en utilisant de free), on n'a pas besoin de vérifier le pointeur, car la fonction le fera elle-même.

Voilà, c'est tout. Un autre bon point pour un développeur débutant est d'utiliser un analyseur en ligne pour comprendre plus rapidement ce qui ne va pas dans le code.

Les questions posées par des développeurs expérimentés et trop tatillons. C'est là que les choses deviennent intéressantes. Cette catégorie de personnes sait ce que la documentation contient. Cependant, ils posent toujours les questions parce qu'ils ne sont pas sûrs que l'appel à free(NULL) est toujours sûr. Ils s'inquiètent que leur code soit compilé sur de très vieux systèmes, où free ne garantit pas une gestion sûre des pointeurs NULL. Ou une bibliothèque tierce particulière qui implémente free d'une manière non standard (en ne vérifiant pas pour NULL) peut être utilisée.

On peut discuter de la théorie. En réalité, cela n'a pas de sens.

Commençons par les anciens systèmes. Tout d'abord, il n'est pas facile de trouver un tel système. La première norme C89 montre que la fonction free doit bien gérer NULL.

C89 : 4.10.3.2 The free function.
La fonction free permet de désallouer l'espace pointé par ptr et le rendre disponible pour une nouvelle allocation. Si ptr est un pointeur NULL, aucune action n'a lieu.

Deuxièmement, si vous voyez un système " pré-norm ", on ne pourra pas créer votre appli pour diverses raisons. Je doute également qu'on n'ait jamais besoin de le faire. Cette issue semble farfelue.

Maintenant, imaginons que le système ne soit pas préhistorique, mais spécial. La bibliothèque tierce inhabituelle de fonctions système qui implémente la fonction free à sa manière : on ne peut pas passer NULL à la fonction.

Dans ce cas, la fonction free brisée n'est pas votre plus grosse issue. Si l'une des fonctions de base du langage est brisée dans la bibliothèque, il y a beaucoup d'autres choses brisées que la dernière chose dont vous devez vous préoccuper est un appel sûr pour free.

C'est comme être dans une voiture artisanale sans freins, sans rétroviseurs et avec un volant bloqué. Mais vous vous inquiétez de savoir si les bornes sont bien connectées à la batterie. Les bornes sont importantes, mais l'issue ne vient pas d'eux, mais de la situation dans son ensemble.

La question de la vérification préliminaire des pointeurs est parfois abordée sous l'angle de la micro-optimisation du code : " Vous pouvez éviter d'appeler la fonction free si vous vérifiez le pointeur vous-même ". C'est là que le perfectionnisme se retourne contre vous. On examine cette idée plus en détail ci-dessous.

Macro du malaise

La chose la plus inutile et potentiellement dangereuse que vous puissiez faire est d'implémenter le contrôle des pointeurs à l'aide d'une telle macro :

#define SAFE_FREE(ptr) if (ptr) free(ptr)

Notre équipe a même une question d'entretien : " Qu'est-ce qui ne va pas avec cette macro ? " Tout y est mauvais. Il semble qu'une telle macro ne devrait pas exister dans la réalité, mais nous l'avons rencontrée dans des projets. Démontons-le un par un.

Tout d'abord, cette macro est une entité redondante.

Comme je vous disais, la fonction free gère bien les pointeurs NULL, et cette vérification ne fournit aucune sécurité supplémentaire lorsque l'on travaille avec des pointeurs.

Deuxièmement, cette macro est également redondante en cas de micro-optimisation.

J'ai lu dans les commentaires que la vérification supplémentaire optimise un peu le code, puisque le compilateur n'a pas à faire un appel coûteux à la fonction free. Je pense qu'il s'agit d'un non-sens et non d'une optimisation.

Le coût de l'appel de fonction est exagéré. Dans tous les cas, ce n'est rien comparé à des opérations consommant des ressources telles que l'allocation et la désallocation de mémoires tampons. En termes d'optimisation, vous devriez vous efforcer de réduire le nombre d'opérations d'allocation de mémoire au lieu de vérifier avant d'appeler la fonction free.

En programmation, le scénario standard est d'allouer la mémoire et de la libérer à nouveau. Les pointeurs NULL passés à free sont très probablement des cas spéciaux, rares et non standard. On n'a pas besoin de les " optimiser ". Une vérification supplémentaire serait très sûrement une pessimisation. En effet, deux vérifications sont effectuées au lieu d'un seul avant que la mémoire ne soit libérée. C'est possible que le compilateur l'optimise, mais ce cas, je ne comprends pas pourquoi on fait tant d'histoires. Au fait, puisque nous parlons d'optimisations, l'optimisation manuelle en utilisant de macros semble naïve et inutile. C'est mieux d'écrire un code simple et compréhensible plutôt que d'essayer de faire des micro-optimisations qu'un compilateur fait mieux qu'un humain.

Je pense que cette volonté d'optimisation superflue confirme la célèbre déclaration de Donald Knuth :

Il ne fait aucun doute que le Graal de l'efficacité conduit à des abus. Les programmeurs perdent énormément de temps à réfléchir ou à s'inquiéter de la vitesse des parties non critiques de leurs programmes, et ces tentatives d'efficacité ont en fait un impact négatif important lorsque l'on prend en compte la debugging et la maintenance. On devrait oublier les petites optimisations locales, disons, 97 % du temps : l'optimisation prématurée est la source de tous les maux.

Troisièmement, la macro provoque des erreurs.

Lorsqu'on utilise la macro, c'est très facile d'écrire un code incorrect.

#define SAFE_FREE(ptr) if (ptr) free(ptr)
....
if (A)
  SAFE_FREE(P);
else
  foo();

Le code ne se présente pas correctement. Étendrons la macro.

if (A)
  if (P) free(P);
else
  foo();

L'instruction else fait référence à la deuxième instruction if et est exécutée lorsque le pointeur est NULL. Eh bien, ils ne se fonctionnent pas comme prévu. La macro SAFE_FREE s'est avérée ne pas être si " SAFE " que cela.

Il y a d'autres façons de créer accidentellement un code incorrect. Examinons le code avec suppression d'un tableau deux dimensions.

int **A = ....;
....
int **P = A;

for (....)
  SAFE_FREE(*P++);
SAFE_FREE(A);

Certes, le code est farfelu, mais il montre comment la macro est dangereuse lorsqu'il s'agit d'expressions complexes. Un pointeur est vérifié et le pointeur suivant est libéré :

for (....)
  if (*P++) free(*P++);

Il y a également un dépassement de tableau.

En résumé, c'est mauvais.

Peut-on fixer une macro ?

On peut, mais on n'en a pas besoin. Examinons les solutions possibles pour y corriger — c'est à des fins éducatives uniquement. C'est aussi l'une des questions que nous posons lors des entretiens.

Tout d'abord, on doit protéger la macro contre l'issue du else. La manière la plus simple, mais la plus inefficace, est d'ajouter des accolades :

#define SAFE_FREE(ptr) { if (ptr) free(ptr); }

Le code dont nous avons parlé plus haut ne sera plus compilé ( l'error: else without a previous if ) :

if (A)
  SAFE_FREE(P);
else
  foo();

On peut utiliser le truc suivant :

#define SAFE_FREE(ptr) do { if (ptr) free(ptr); } while(0)

Le code se compile à nouveau. La première issue est résolue, mais qu'en est-il des nouveaux calculs ? Une solution standard recommandée n'existe pas. Toutefois, il y a des solutions de rechange si vous le souhaitez vraiment.

Une issue similaire se pose lors de la mise en œuvre de macros telles que max. Voici un exemple :

#define max(a, b) ((a) > (b) ? (a) : (b))
....
int X = 10;
int Y = 20;
int Z = max(X++, Y++);

21 au lieu de 20 seront écrites dans la variable Z parce que la variable Y aura été incrémentée au moment de la sélection :

int X = 10;
int Y = 20;
int Z = ((X++) > (Y++) ? (X++) : (Y++));

Pour éviter cela, on peut utiliser la magie : l'extension du compilateur GCC : referring to a Type with typeof.

#define max(a,b) \
  ({ typeof (a) _a = (a); \
      typeof (b) _b = (b); \
    _a > _b ? _a : _b; })

Il s'agit de copier des valeurs dans des variables temporaires et d'éliminer ainsi le calcul répété d'expressions. L'opérateur typeof est un analogue du decltype C++, mais pour C.

Une fois encore, notez qu'il s'agit d'une extension non standard. Je ne recommande pas de l'utiliser à moins d'en avoir vraiment besoin.

Appliquons cette méthode à SAFE_FREE :

#define SAFE_FREE(ptr) do { \
  typeof(ptr) copy = (ptr); \
  if (copy) \
    free(copy); \
} while(0)

Cela fonctionne. Mais j'ai dû écrire un code terrible, insupportable et en fait inutile pour le faire.

Une solution plus élégante consiste à convertir la macro en fonction. De cette manière, on peut éliminer les issues évoquées ci-dessus et simplifier le code :

void SAFE_FREE(void *ptr)
{
  if (ptr)
    free(ptr);
}

Attendez, attendez, attendez ! On revient à l'appel de fonction ! Sauf que maintenant, on a une couche de fonction supplémentaire. La fonction free effectue le même travail de vérification du pointeur.

La meilleure façon de corriger la macro SAFE_FREE est donc de la supprimer !

Remise à zéro du pointeur après free

Il y a un sujet qui n'a presque rien à voir avec la vérification des pointeurs, mais discutons-en également. Certains programmeurs recommandent de remettre à zéro le pointeur après la libération de la mémoire. Au cas où.

free(pfoo);
pfoo = NULL;

On pourrait dire que le code est écrit selon le paradigme de la programmation défensive. Je parle d'actions optionnelles extra qui permettent parfois de se prémunir contre les erreurs.

Dans notre cas, si le pointeur pfoo n'est pas utilisé, il est inutile de le mettre à zéro. Toutefois, on peut le faire pour les raisons suivantes.

L'accès aux pointeurs. Si des données sont écrites accidentellement dans le pointeur, il ne s'agit pas d'une corruption de la mémoire, mais d'un déréférencement du pointeur NULL. Une telle erreur est détectée et corrigée plus rapidement. La même chose se produit lors de la lecture de données à partir d'un pointeur.

Double-free. La mise à zéro du pointeur protège contre les erreurs lorsque le tampon est à nouveau libéré. Cependant, les avantages ne sont pas aussi évidents au premier coup d'œil. Examinons le code qui contient l'erreur :

float *ptr1;
char *ptr2;
....
free(ptr1);
ptr1 = NULL;
....
free(ptr1);  // la variable ptr2 doit être utilisée ici
ptr2 = NULL;

Un développeur a fait une erreur : au lieu d'écrire ptr2, on a utilisé le pointeur ptr1 pour libérer à nouveau de la mémoire. En raison de la mise à zéro du pointeur ptr1, rien ne se produit lorsque vous le libérez à nouveau. Le code est protégé contre l'erreur double-free. En revanche, la mise à zéro du pointeur cache l'erreur plus profondément. Il y a une fuite de mémoire qui peut être difficile à détecter.

La programmation défensive est critiquée à cause de ces cas (masquer les erreurs, remplacer une erreur par une autre). C'est un vaste sujet, et je ne suis pas prêt à m'y plonger. Cependant, je pense qu'il est juste de vous mettre en garde contre les inconvénients de la programmation défensive.

Quelle est la meilleure façon de procéder si vous décidez de remettre à zéro les pointeurs après avoir libéré la mémoire ?

Commençons par la manière la plus dangereuse :

#define FREE_AND_CLEAR(ptr) do { \
  free(ptr); \
  ptr = NULL; \
} while(0)

La macro n'est pas conçue pour être utilisée de cette manière :

int **P = ....;
for (....)
  FREE_AND_CLEAR(*P++);

Un pointeur est libéré et le pointeur suivant est mis à zéro. Polissons la macro :

#define FREE_AND_CLEAR(ptr)  do { \
  void **x = &(ptr); \
  free(*x); \
  *x = NULL; \
} while(0)

Il fait l'affaire, mais franchement, ce genre de macro n'est pas mon truc. Je préférerais que le pointeur soit explicitement mise à zéro :

int **P = ....;
for (....)
{
  free(*P);
  *P = NULL;
  P++;
}

Le code ci-dessus est trop long, je ne l'aime pas. Il n'y a pas de magie macro. ! Je n'aime pas les macros. Le fait que le code soit long et laid est une bonne raison d'envisager sa réécriture. Est-il vraiment nécessaire d'itérer et de libérer des pointeurs d'une manière aussi maladroite ? Nous pourrions peut-être rendre le code plus élégant. C'est une bonne raison de procéder à un remaniement.

Conclusion

N'essayez pas de résoudre des issues inventées à l'avance et au cas où. Écrire un code simple et clair !

  • # Droit ?

    Posté par  (site web personnel, Mastodon) . Évalué à 7 (+4/-0).

    Le site est marqué : ©2008 - 2024, PVS-Studio LLC.

    A priori, sans autre information, il me semble qu'il n'est pas possible de diffuser une traductions sans l'autorisation des auteurices.

    « Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.

    • [^] # Re: Droit ?

      Posté par  . Évalué à 1 (+1/-0).

      Bonjour !

      Votre remarque est juste, je m'en excuse. Cependant, l'autorisation de traduire a été obtenue de l'auteur. Je pense que je le signalerai dans la remarque. Merci de l'avoir noté !

      • [^] # Re: Droit ?

        Posté par  (site web personnel) . Évalué à 5 (+2/-0).

        Autorisation y compris de changer la licence pour mettre une Licence CC By‑SA 4.0 sur la traduction ?

        • [^] # Re: Droit ?

          Posté par  . Évalué à 1 (+1/-0).

          Je m'excuse, je ne l'ai pas mentionné dans la remarque. L'auteur a autorisé la traduction et la publication de l'article sous la licence que vous avez mentionnée. C'est une omission de ma part, en tant que traductrice, de ne pas l'avoir mentionné.

          J'aimerais la corriger dans la note, mais malheureusement, je ne trouve pas où la corriger. Je l'écris donc ici.

          Encore une fois, toutes mes excuses au web site.

          • [^] # Re: Droit ?

            Posté par  (site web personnel) . Évalué à 6 (+4/-0).

            Bonjour,

            Ce journal est le bienvenu. Pour vos prochains journaux de ce type il faudrait commencer par quelque chose du genre « Ce journal est une traduction de <insérer la source> avec l'accord de l'auteur initial ». Il serait bon aussi d'apporter une preuve de l'accord pour la traduction et pour le changement de licence de diffusion :)

    • [^] # Re: Droit ?

      Posté par  . Évalué à 3 (+1/-0).

      J'ai abouti aux mêmes conclusions, en lisant https://pvs-studio.com/fr/terms-of-use/

  • # Article traduit par un ou une humain.e ?

    Posté par  (site web personnel, Mastodon) . Évalué à 8 (+6/-0).

    Les formulations des phrases sont assez étrange, cet article a-t-il été traduit par un humain ?

    De la à se demander si l'article initial a été généré il n'y a qu'un pas …

    J'ai plus qu'une balle

    • [^] # Re: Article traduit par un ou une humain.e ?

      Posté par  (site web personnel) . Évalué à 7 (+5/-0).

      Même remarque. La traduction n’est vraisemblablement pas faite par un francophone. Probablement plutôt par un outil de traduction automatique. Mais à quelles fins ? Pouvoir ensuite poster des contenus SEO sur Linuxfr ?

      « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

    • [^] # Re: Article traduit par un ou une humain.e ?

      Posté par  . Évalué à 2 (+4/-2).

      Excusez-moi, chère communauté.

      Oui, je ne suis pas francophone. Je suis juste une traductrice française débutant qui voulait s'essayer à la traduction en français.

      Oui, ma traduction est présente sur le site, car je suis le traducteur de ce web site.

      Je m'excuse que vous ayez été incommodé par ma traduction. Je me suis rendu compte que je devais encore développer mes compétences.

      Merci pour vos commentaires.

    • [^] # Re: Article traduit par un ou une humain.e ?

      Posté par  (site web personnel) . Évalué à 10 (+13/-0). Dernière modification le 24 avril 2024 à 17:05.

      Sommaire

      La langue française

      J’ai tiqué sur l’utilisation récurrente du mot « issue » pour tout un tas de choses différentes, comme « problématique », « problème », « souci », « préoccupation », « bug », « erreur » ou « question ».

      Deuxièmement, si vous voyez un système " pré-norm ", on ne pourra pas créer votre appli pour diverses raisons. Je doute également qu'on n'ait jamais besoin de le faire. Cette issue semble farfelue.

      Dans ce cas, la fonction free brisée n'est pas votre plus grosse issue.

      Les bornes sont importantes, mais l'issue ne vient pas d'eux

      Tout d'abord, on doit protéger la macro contre l'issue du else.

      Une issue similaire se pose lors de la mise en œuvre de macros telles que max.

      De cette manière, on peut éliminer les issues évoquées ci-dessus et simplifier le code

      N'essayez pas de résoudre des issues inventées à l'avance et au cas où

      Il faudrait écrire :

      Deuxièmement, si vous voyez un système " pré-norm ", on ne pourra pas créer votre appli pour diverses raisons. Je doute également qu'on n'ait jamais besoin de le faire. Cette préoccupation semble farfelue (« question » est acceptable)

      Dans ce cas, la fonction free brisée n'est pas votre plus gros souci (« problème » est acceptable)

      Les bornes sont importantes, mais le risque ne vient pas d'eux (« problème » est acceptable)

      Tout d'abord, on doit protéger la macro contre le bug du else.

      Une question similaire se pose lors de la mise en œuvre de macros telles que max. (« problématique » est acceptable si on utilise le verbe « se présente »)

      De cette manière, on peut éliminer les erreurs évoquées ci-dessus et simplifier le code

      N'essayez pas de résoudre des problèmes inventés à l'avance et au cas où

      Je doute d’ailleurs que « au cas où » soit correct en français et signifie ce que l’auteur voulait dire. Par exemple la phrase « Il n'y a pas de magie macro » n’est pas correcte en français. Cet article peut-être pas traduit de l’anglais, ou si cela l’est l’anglais n’est peut-être pas la langue natale de l’auteur. Car je pense en effet qu’en anglais on dirait « magical macro » qui se traduirait naturellement en « macro magique », et jamais « magie macro ».

      Il serait aussi idiomatiquement plus juste de dire « Essayez de ne pas vous inventer des problème ».

      J’aurai aimé que le journal mette le lien vers l’article d’origine (d’autant plus qu’il y a déjà un autre lien vers un autre article du blog de PVS Studio)… Je l’ai trouvé et… il est déjà dans ce français bizarre. Je ne l’ai pas (encore ?) trouvé dans une autre langue.

      SEO ?

      Si c’est du SEO, ça ne semble être à l’initiative de PVS, car à leur profit. Par exemples les autres liens de l’article sont soit Wikipédia, soit la doc de GCC, soit…

      Le troisième lien mène vers un article (en anglais) sur un autre sujet et sur autre blog mais qui est déjà lié dans l’article de PVS sur le site de PVS. J’écarte donc l’idée que ce soit l’auteur de cet autre blog qui aurait copié/collé l’article de PVS pour y insérer un lien vers son propre blog. SAUF QUE, l’auteur de cet article (mars 2019) sur cet autre blog est signé du même auteur (Andrey Karpov ) que l’article sur le site de PVS (favrier 2024), on peut considérer que c’est aussi un article de PVS, l’autre blog étant d’ailleurs un blog personnel au nom d’une autre personne (Anne Mertz). Cet autre article est d’ailleurs la seule contribution d’Andrey Karpov sur le blog d’Anne Mertz.

      Pour ceux qui ne sont pas au fait de certaines pratiques SEO, voici le courriel que j’ai reçu la semaine dernière :

      Bonjour à tous,
      Pouvez-vous m'indiquer les tarifs et les conditions pour faire publier un article sur illwieckz.net ?
      Le site semble convenir parfaitement à la campagne d'un client important sur laquelle je travaille et nos rédacteurs internes sont en mesure de créer un article de très bonne qualité en fonction de votre public, afin de s'assurer qu'il vous conviendra également.
      Comme nous disposons de plusieurs autres clients de premier plan qui cherchent à améliorer leur marque par le biais d'un contenu éditorial dans ce créneau, nous sommes aptes à de vous proposer d'autres opportunités par la suite, si vous êtes ouvert à cette idée.
      Voici deux exemples d'articles récents réalisés par nos soins : [caviardé]
      J'attends avec impatience vos informations sur les tarifs ; vous pouvez également me faire savoir si vous préférez en parler de vive voix au téléphone.
      Je vous remercie.

      Je reçois ce genre de demande depuis des années pour unvanquished.net

      Donc ça ressemble à du SEO, payant ou pas (ça peut aussi être des gens qui se connaissent).

      Mon avis ?

      Dans l’absolu je n’ai pas de problème à ce que des gens publient des articles intéressants et que cela contribue à leur référencement, c’est un échange de bon procédé.

      En soit l’article est utile, le sujet n’est pas déconnant, ça reste instructif, et je le trouve plutôt adapté au public de LinuxFr. Si par exemple c’est PVS Studio qui est derrière ce journal, je ne suis pas opposé par principe à ce que PVS Studio contribue à LinuxFr.org si le sujet correspond aux sujets usuellement traités.

      Sur leur site il est écrit :

      Notre équipe a analysé plusieurs projets open-source et a publié les résultats. Nous soutenons et encourageons les projets open-source : nous informons les développeurs open-source des bugs qui ont été trouvés. Nous les aidons à configurer notre analyseur pour vérifier leur code. Ils ont une [page dédiée] pour cela et ils listent des projets libres comme Haiku, Firefox, Blender, Qt, PHP, Apache, LLVM, les moteurs de jeu Unreal, Unity et Cry…

      Ni le projet de jeu vidéo libre Unvanquished ni son moteur de jeu Dæmon ne sont cités. Je ne sais pas si nous avons été aidés par leur équipe, ou si la personne qui nous a aidé était un tiers, mais entre 2017 et 2020 quelqu’un est venu régulièrement nous soumettre des suggestions de corrections après analyse de notre base de code avec PVS studio (voir sur les trackers Unvanquished, Dæmon), commits qu’on a consciencieusement relus et parfois adaptés.

      Les PR mentionnaient systématiquement :

      Product Page: [lien]
      How to use for free: [lien]

      Ce qui pourrait être mentionné ainsi soit parce que rédigé par quelqu’un de PVS Studio, soit parce que PVS Studio poserait cette condition à l’utilisation du logiciel.

      Je n’ai trouvé aucune information permettant de lier l’auteur des contributions et utilisateur de PVS Studio à PVS Studio. Il est aussi possible que ce soit simplement un tiers qui aime bien ce logiciel. Cette personne a aussi des projets bien à lui.

      Tout comme la contribution d’article, je ne suis pas opposé à ce que PVS Studio contribue à des logiciels libres et que par effet de bord cela fasse leur promotion. Toutes les contributions en code soumise à Unvanquished et Dæmon étaient bienvenues, et il est bienvenu d’avoir des contributeurs qui font de l’analyse et revue de code, comme d’avoir des contributeurs qui écrivent des articles sur des bonnes pratiques de programmation.

      Par contre je pense qu’il est légitime d’exiger que :

      • L’auteur de la contribution soit clairement désigné ;
      • Le texte soit rédigé / traduit par un être humain.

      Ici le texte est très certainement rédigé par un être humain, mais la traduction semble être faite par un logiciel. L’assistance d’un logiciel n’est pas un problème à mes yeux, mais je suis convaincu qu’un humain doit toujours contrôler et corriger éventuellement ce que fait le logiciel.

      On peut comparer avec ce que fait le compte MariePa pour OnlyOffice. Ce journal a été considéré par certains comme une tentative de publicité déguisée (et quelqu’un avait ajouté le tag publireportage), mais globalement, les choses sont assez claires. Les dépêches OnlyOffice semblent clairement écrites par quelqu’un de chez OnlyOffice, et MariePa ne publie que des articles sur OnlyOffice. Les dépêches sont modérées, éventuellement éditées et validées par l’équipe de modération. Je trouve ça plutôt honnête et sain, et je préfère encourager ces entreprises à entrer dans un cercle vertueux où tout le monde est gagnant, à condition de respecter les règles simples que je viens d’énumérer, auxquelles on peut ajouter une troisième :

      • Éviter le jargon de communiquant et respecter les conventions du site/attentes rédactionnelles de la communauté.

      MariePa a su prendre le pli pour limiter le jargon de communiquant, éviter un minimum certaines formes insupportables du publireportage, et se plie globalement aux convenances du site, et aux attentes de la communauté.

      Si PVS Studio est à l’origine de ce journal, s’ils s’identifient clairement et font les mêmes efforts que MariePa, je ne serai pas personnellement opposé à ce qu’ils puissent contribuer un article, journal ou dépêche.

      À rappeler que PVS Studio n’est pas libre, mais est disponible sous Linux. Linux étant un des thèmes majeurs de ce site (libre ou non), et la programmation étant un sujet récurrent, je ne suis pas opposé à ce genre de journal qui traite de programmation écrit par un acteur dont le produit n’est pas libre mais qui est disponible sous Linux. Et si ça leur fait du référencement en retour ça n’est pas foncièrement malhonnête.

      Par contre il est important de ne pas tromper les gens, ce qui serait malhonnête serait de prendre les gens pour des cons.

      J’apprécierai donc que mari.h soit plus clair sur ses intentions et ses relations éventuelles avec PVS Studio. Il n’y a pas de honte à travailler pour PVS Studio, et si c’est le cas, il serait même plus utile de clairement honorer leur volonté de contribution.

      Au lieu de générer de la suspicion cela pourrait même générer de la gratitude. Je préfère les relations claires, plutôt qu’un jeu de chat et souris honte-suspicion, les relations claires et transparents ont plus de chance d’aboutir à un échange gagnant-gagnant, éventuellement une collaboration franche et enthousiaste (ça y est je commence à cocher les cases du bingo 🤣️).

      ce commentaire est sous licence cc by 4 et précédentes

      • [^] # Re: Article traduit par un ou une humain.e ?

        Posté par  (site web personnel) . Évalué à 8 (+5/-0).

        Erratum :

        Si c’est du SEO, ça ne semble être à l’initiative de PVS, car à leur profit.

        Je voulais dire :

        Si c’est du SEO, ça semble être à l’initiative de PVS, car à leur profit.

        Ou :

        Si c’est du SEO, ça ne semble pas être à l’initiative de quelqu’un d’autre que PVS, car le référencement généré ne profite pas vraiment à d’autres.

        Les deux phrases se sont mélangées dans ma tête et j’ai écrit la moitié de l’une et la moitié de l’autre, faisant un cotnre-sens. 😅️

        ce commentaire est sous licence cc by 4 et précédentes

      • [^] # Re: Article traduit par un ou une humain.e ?

        Posté par  (site web personnel) . Évalué à 6 (+3/-0).

        À noter que le site d’Arne Mertz (où Andrey Karpov a publié un article lié dans ce journal) a une page qui exclu les contributions commerciales:

        I regularly get email requests from professional guest post writers who promise clicks, money, engagement, interesting and relevant content in exchange for an opportunity to write a guest post. If you are one of those authors, I am sorry, I’m not looking for that kind of guest post. If you are a developer though and want to write about something relevant to this blog and not about how tech disrupts the industry or how to use C pointers, please read on.

        D’ailleurs c’est Arne Mertz (Arn comme Arnold), pas Anne Mertz.

        ce commentaire est sous licence cc by 4 et précédentes

      • [^] # Re: Article traduit par un ou une humain.e ?

        Posté par  (Mastodon) . Évalué à 10 (+7/-0).

        L’auteur de la contribution soit clairement désigné ;

        En cherchant un peu, je pense qu'on peut affirmer que l'auteur mari.h est Mariya Hlopova qui travaille chez PVS-Studio en tant que traductrice.

        https://pvs-studio.com/fr/blog/posts/?author=mariya-hlopova

        PVS-Studio a un certain talent (pour être gentil) pour faire des articles qui ressemble à des articles mais qui sont de la publicité déguisée pour leur outil. Souvent, ça se résume à : «Regardez ce code tout pas beau avec un bug très difficile à trouver ! Avec PVS-Studio, on le trouve très facilement !»

      • [^] # Re: Article traduit par un ou une humain.e ?

        Posté par  . Évalué à 10 (+12/-0).

        Bonjour à nouveau.

        Merci beaucoup pour tous ces commentaires.
        Je vais clarifier un peu les situations pour éviter d'autres incompréhensions.

        Je suis traductrice pour PVS-Studio. Je travaille dans cette entreprise et Andrey Karpov est l'un de nos gestionnaires. Il a écrit de nombreux articles théoriques sur la programmation et le langage C++ et, en tant que traductrice, j'ai voulu distribuer ses articles à un plus grand nombre de développeurs. Nous écrivons activement des articles en anglais afin que davantage de personnes puissent découvrir des choses intéressantes dans différents langages de programmation ainsi que ce que nous faisons, à savoir l'analyse statique.

        Je suis une traductrice débutante qui a commencé son voyage professionnel il y a environ six mois. Le français n'est pas ma langue principale pour la traduction, et encore moins ma langue natale.

        Et à propos de la remarque. La prochaine fois, je ferai une remarque sur tous les points que vous avez énumérés.

        Merci beaucoup pour vos commentaires utiles. Ces commentaires m'aident à m'améliorer comme traductrice :)

  • # Sauvons SAFE_FREE !

    Posté par  . Évalué à 10 (+12/-0).

    Tada :o) !

    #define SAFE_FREE(ptr) free(ptr)
  • # Cas plus concrets

    Posté par  . Évalué à 4 (+2/-0). Dernière modification le 24 avril 2024 à 22:17.

    Je ne sais pas trop quoi penser de l'article, je suis d'accord avec tous les exemples, mais il me titille quand même.

    Déjà pour l'histoire des macros, évidemment, ce sont de très mauvaises macro à éviter absolument, mais ça n'a rien à voir avec le sujet de free, mais dans d'autres contextes (et l'exemple de la macro max le montre bien), ce genre de macro est à proscrire.

    Ensuite le tests avant le free, perso je me suis reconnu dans le cas "débutant", je me souviens encore dans mes jeunes années de dev quand j'ai appris que free (pour rêtre honnete, dans mon cas c'était delete du c++) vérifiait si le pointeur n'était pas null et j'ai arreté de faire la vériication à chaque fois.
    Mais dans la pratique, il arrive souvent que dans les phases de nettoyage on ne fasse pas qu'un free, exemple :

    if ( ptr != NULL ) {
        do_something(ptr);
        free(ptr);
    }
    

    Alors oui, le free peut-être sorti du bloc if, mais en terme de lisibilité, je trouve ça vraiment mieux de l'y laisser.

    Et pour ce que tu appelles la programmation défensive (bizarre comme terme, ça existe la programmation offensive où on cherchce volontairement à se mettre dans des situations compliquées ???) c'est pareil : dans la pratique, mettre le pointeur à NULL c'est un flag qui permet de connaitre un état local pour le gérer correctement quand je ré-entre dans ce code, je le fait très régulièrement et je trouve que c'est une pratique très saine, simple d'utilisation et très utile.

    Pour en revenir à l'article, j'ai l'impression que l'auteur prend des cas d'utilisation pourris pour appuyer ses arguments. Je peux faire à peu près pareil avec beaucoup de pratiques de code, de fonctions ou d'objet des librairies standard. Oui, quand on s'en sert mal, ç'est pas bien. (variante du : "c'est pas gentil d'être méchant")
    Des questions intéressantes, pour toute critique sur des pratiques de code, seraient plutôt :
    - est ce qu'il est trop facile de mal s'en servir même pour quelqu'un de pas complètement débutant ?
    - quels sont les cas utiles, intéressants, et est-ce qu'il sont assez importants pour accepter qu'il y ait des limitations, revers à l'utilisation.
    - est ce qu'il n'est pas plus intéressant de comprendre dans quel contexte cela est utile, pour savoir dans lesquels on peut s'en passer ? (typiquement l'idée du livre sur "design patterns" pour des cas un peu plus complexes et précis)

    • [^] # Re: Cas plus concrets

      Posté par  . Évalué à 7 (+4/-0).

      bizarre comme terme,

      Hou la malheureux, oui la programmation défensive est un terme; je l'avais surtout croisé en java, où les gens se mettent à copier des objets dans tous les sens au cas où une personne déciderai de le modifier suite a une mauvaise compréhension de ce qu'est la programmation défensive.

      Résultat, on a d'autre nœuds au cerveau et une explosion de la mémoire et des heures à comprendre pourquoi ça marche pas, parce qu'un boulet n'a pas fait une copie profonde, ou des objets désynchronisé car ce qui aurait du être qu'une seule map a été copié alors qu'elle n'aurait pas du.

      pour aller plus loin Defensive_programming

      C'est un peu léger, mais ça répond a 2 de tes question (sur l'existence de la programmation offensive notamment :) qui est une sorte de programmation défensive si vis pacem para bellum )

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: Cas plus concrets

      Posté par  . Évalué à 3 (+1/-0).

      Déjà pour l'histoire des macros, évidemment, ce sont de très mauvaises macro à éviter absolument

      Comme la plupart des macros, en fait.
      Dès lors que le bloc "macroifié" n'utilise pas les éléments de syntaxe du pré-processeur (concaténation, stringification, __DATE__, __LINE__, __FILE__,…) alors il vaut souvent mieux utiliser des fonctions, quitte a les mettre dans le header avec un inline bien senti.
      Plus facile a aligner, pas besoin de s'emm… avec les continuations de ligne (parce que #define ne travaille que sur une ligne, donc il faut \\ le retour chariot OU faire un one-liner. Dans les deux cas, la lisibilité en prend un coup), se base sur le compilateur qui est plus intelligent que le pré-processeur (type-safety, notamment), isolation des variables (une macro ne limite pas la portée, une fonction si) qui implique qu'on risque moins de "shadow" autre chose par accident parce qu'on a oublié d'utiliser le workaround do { ... } while (false) (ou qu'on a malencontreusement ajouté un ; à la fin, même si ça, au moins, ne générera pas de bugs a ma connaissance)…

      Et pour ce que tu appelles la programmation défensive (bizarre comme terme, ça existe la programmation offensive où on cherchce volontairement à se mettre dans des situations compliquées ???)

      Je confirme que ça existe, j'en ai entendu parler à plus d'un endroit. Le concept m'a toujours semblé un peu flou, ceci dit.
      Parce que bon, moi aussi, je teste le retour d'erreur de la plupart de mes fonctions… (pas toutes, j'ai souvent la flemme avec printf(), par exemple) et je n'ai pas l'impression d'être spécialement défensif: c'est surtout histoire d'avoir des logs utilisables quand ça va bugguer (parce que ça finit toujours par bugguer), plutôt que de devoir galérer a trouver une repro au pifomètre… puis un log bien fait, c'est quand même plus simple à lire qu'un coredump…

      Je suis aussi d'accord sur la remise à zéro du pointeur. C'est un truc qu'il m'arrive de faire, notamment quand j'ai affaire a des conteneurs "fait main": je préfère une RàZ inutile plutôt que passer des heures a trouver d'où viens un bug, tout ça pour m'apercevoir que le pointeur est libéré 2 fois, utilisé alors qu'il devrait être invalide, ou ce genre de joyeusetés… C'est particulièrement pertinent en C, d'ailleurs, qui n'offre aucun moyen de gérer ce genre de besoins basiques automatiquement. Un jour, peut-être, il sera possible d'écrire du C sans se farcir ces infâmes piles de labels pour la gestion d'échec. Mais d'ici la, je continuerai a considérer le C comme un artefact du passé.
      Je préfère perdre quelques cycles à xor un emplacement mémoire, que des heures a débuguer un truc dont la reproduction est aléatoire (autant j'aime les grosses segfault qui tâchent, facile a choper, vous savez, celles qu'on reproduit trivialement… autant les autres types de corruption mémoire j'aime pas!).

  • # et double-free() ?

    Posté par  (site web personnel) . Évalué à 3 (+1/-0).

    Qu'en est-il de la fonction double-free() ?

    pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.