Pourquoi C ne vous empêchera pas de faire des erreurs



En bref: parce que nous l'avons dit.



:)



D'accord, c'est une explication trop courte pour un article, cher lecteur, et mes paroles provocantes nécessitent une explication.



La réunion du Comité de la langue C - qui devait initialement se tenir à Fribourg, en Allemagne, mais qui n'a pas grandi ensemble pour des raisons évidentes - s'est terminée le 7 août. Cela s'est bien passé, nous avons progressé sur tous les fronts. Oui, nous progressons effectivement, je vous l'assure, et C n'est pas mort.



Je mentionnerai également que je suis devenu l'éditeur du projet C, donc avant de prendre le titre comme une déclaration ignorante de quelqu'un qui est trop paresseux pour "essayer de s'améliorer", je tiens à vous assurer que je travaille vraiment très dur pour que C pour satisfaire les besoins des développeurs sans avoir à visser 50 extensions spécifiques dans le but de construire des bibliothèques et des applications plus ou moins belles et utiles.



Et pourtant je l'ai dit (que le langage C ne vous empêchera jamais de faire des erreurs), ce qui signifie que je dois justifier. Nous pouvons examiner des milliers de CVE et des tickets associés avec un tas de code C, ou nous pouvons demander à MISRA de vérifier vigoureusement chaque fonctionnalité C pour une utilisation abusive potentielle ( bonjour, déclarations de prototype K&R...) ou des bogues plus complexes et amusants liés à la portabilité et au comportement indéfini. Mais au lieu de cela, nous lisons la source originale - ce que le Comité lui-même a dit.



Oh, il est temps d'acheter du pop-corn?!



Non cher lecteur, mettez le pop-corn de côté. Comme pour toutes les procédures ISO, je ne peux citer les propos de personne d'autre, et cet article ne vise à faire honte à personne. Mais je vais vous expliquer pourquoi quelque chose que nous pourrions facilement considérer comme un mauvais comportement dans un document ISO C conforme aux normes ne sera jamais exclu. Et commençons par le document du Dr Philipp Klaus Krause:



N2526, utilisez const pour les données de bibliothèque qui ne seront pas modifiées .



N2526 est un document très simple.



, , , . — , ! …


Je suis d'accord, ce n'est pas exactement la même chose, mais je suis sûr que l'idée vous semblera raisonnable, cher lecteur. Lorsque ce document a été mis aux voix, il n'y a pratiquement pas eu de votes contre. Plus tard, plusieurs personnes se sont fortement opposées car cette proposition cassait l'ancien code. Bien sûr, c'est mauvais: même je reprends mon souffle quand je pense à ajouter const? Il n'y a pas d'ABI dans le langage C qui puisse être influencé par l'innovation. C (sa mise en œuvre) ne fait même pas attention aux qualificatifs, comment peut-on casser quelque chose?! Voyons pourquoi certaines personnes pensent que ce sera un changement radical.



Langue C



Ou, comme j'aime l'appeler, «la sécurité de type est pour les langues défaillantes». Oui, trop verbeux, arrêtons-nous donc à "C". Vous vous demandez peut-être pourquoi je dis que des langages comme C ne sont pas sûrs. Après tout, voici:



struct Meow {
    int a;
};

struct Bark {
    double b;
    void* c;
};

int main (int argc, char* argv[]) {
    (void)argc;
    (void)argv;

    struct Meow cat;
    struct Bark dog = cat;
    // error: initializing 'struct Bark' with an expression of incompatible type 'struct Meow'

    return 0;
}


Pour être honnête, cela me semble être une sécurité de type fort, Jim! Et ainsi tout devient encore plus piquant:



#include <stdlib.h>

struct Meow {
    int a;
};

struct Bark {
    double b;
    void* c;
};

int main (int argc, char* argv[]) {
    (void)argc;
    (void)argv;

    struct Meow* p_cat = (struct Meow*)malloc(sizeof(struct Meow));
    struct Bark* p_dog = p_cat;
    // :3
    
    return 0;
}


Oui, la norme C permet à deux types de pointeurs complètement indépendants de se référer l'un à l'autre. La plupart des compilateurs vous en avertiront, mais la norme vous oblige à accepter ce code à moins que vous ne vous détendiez -Werror -Wall -Wpedantic, etc., etc., etc.



En fait, le compilateur peut accepter cela sans cast explicite:



  • volatile (qui a besoin de cette sémantique?!)
  • const (écrivez ici toutes les données en lecture seule!)
  • _Atomic (sécurité du fil!)


Je ne dis pas que vous ne devriez pas pouvoir faire tout cela. Mais lorsque vous écrivez en C - dans lequel il est très facile de créer une fonction de 500-1000 lignes avec des noms de variables totalement incompréhensibles - Infa Sotka, que vous travaillez principalement avec des pointeurs, et vous manquez généralement de sécurité en termes de langage de base. Remarque: cela enfreint les restrictions, mais tant de vieux code a déjà été écrit que chaque implémentation ignore en quelque sorte les qualificatifs, et à cause de cela, votre code ne sera pas empêché de se compiler ( merci @fanf!)! Dans cette situation, il est possible avec le compilateur d'identifier facilement chaque échec potentiel, et vous recevrez des avertissements, mais vous ne serez pas obligé de faire un typage afin de faire savoir au compilateur ce que vous vouliez vraiment faire. Plus important encore, les êtres humains qui viendront après vous ne comprendront pas non plus ce que vous avez décidé de faire.



Tout ce que vous avez à faire est de supprimer la fonctionnalité -Werror -Wall -Wpedanticet vous serez prêt à commettre les crimes du multithreading, du mode lecture seule et des registres matériels.



Tout est juste maintenant, non? Si quelqu'un supprime tous ces indicateurs d'avertissement et d'erreur, il ne se souciera pas du genre de faux pas ou de choses stupides que vous faites. Cela signifie qu'en fin de compte, ces avertissements sont totalement inutiles et inoffensifs en ce qui concerne la conformité à la norme ISO C. Et pourtant ...



Nous envisageons de briser les avertissements



Oui.



C'est un enfer spécial auquel les développeurs C et, dans une moindre mesure, les développeurs C ++ sont habitués. Les avertissements sont ennuyeux et, comme le montre la pratique, y compris -Weverythingou /W4, très ennuyeux. Masquer les avertissements de variables dans l'espace de noms global (merci, maintenant tous les en-têtes et bibliothèques C sont un problème), en utilisant des noms "réservés" (comme les enfants disent, " lol nice one xd !! "), et "cette structure a un remplissage parce que vous avez utilisé alignof"(... oui, oui, je sais qu'elle a un rembourrage, j'ai explicitement demandé plus de rembourrage, PARCE QUE J'AI UTILISÉ alignof, M. COMPILATOR) - tout cela prend beaucoup de temps.



Mais ce sont des avertissements.



Même s'ils sont ennuyeux, ils vous aident à éviter les problèmes. Le fait que je puisse ignorer sans vergogne tous les qualificatifs et négliger toutes sortes de sécurité en lecture, en écriture, en streaming et en lecture seule est une préoccupation majeure lorsqu'il s'agit de communiquer mes intentions et d'éviter les bogues. Même l'ancienne syntaxe K&R a conduit à des bogues dans les bases de code industrielles et gouvernementales parce que les utilisateurs faisaient quelque chose de mal. Et ils l'ont fait non pas parce qu'ils étaient de mauvais programmeurs, mais parce qu'ils travaillent avec des bases de code souvent plus anciennes qu'eux et se préparent à se battre avec celles-ci. longs millions de lignes. Il est impossible de garder toute la base de code dans votre tête: les conventions, l'analyse statique, les avertissements de haut niveau et d'autres outils sont pour cela. Malheureusement,



tout le monde veut avoir un code sans avertissement.



Cela signifie que lorsque le développeur GCC rend les avertissements plus sensibles aux situations potentiellement problématiques, les responsables (pas les développeurs d'origine) reçoivent de manière inattendue des journaux en gras de plusieurs gigaoctets de l'ancien code, contenant beaucoup de nouveaux avertissements et toutes sortes de choses différentes. "C'est de l'idiotie", disent-ils, "le code a fonctionné pendant des ANNÉES alors pourquoi GCC se plaint-il maintenant?" Autrement dit, même si vous ajoutez des constfonctions à la signature, même si elle est moralement, spirituellement et réellement correcte, cela sera évité. «Briser» les gens signifie «maintenant qu'ils doivent chercher un code qui a des intentions douteuses». C'est du code qui peut - sous peine de comportement indéfini - détruire votre puce ou endommager votre mémoire.... Mais c'est un autre problème qui accompagne la profession de C-développeur ces jours-ci.



L'âge comme mesure de la qualité



Combien de personnes ont même supposé qu'elles sudoavaient une vulnérabilité primitive telle que "-1 ou un débordement d'entier donne accès à tout"? Combien de personnes pensaient que Heartbleed pouvait être un vrai problème? Combien de développeurs de jeux proposent de «petites» bibliothèques stb sans même les phaser et sans se rendre compte que ces bibliothèques contiennent des vulnérabilités d'entrée plus importantes que vous ne l'imaginez? Je ne critique pas tous ces développements ou leurs auteurs: ils nous fournissent une aide vitale dont le monde a dépendu pendant des décennies, souvent avec peu ou pas de soutien jusqu'à ce qu'un gros problème se pose. Mais les gens qui idolâtrent ces développements et les mettent seuls, puis suintent un dicton empoisonné d'eux-mêmes, illustrant l'erreur du survivant:



, ?


En gardant les principes de compatibilité ascendante et «détendus» comme les idéaux les plus élevés de C, les gens qui survivent assez longtemps dans cette industrie commencent à assimiler âge et qualité, comme les bases de code sont des tonneaux de vin. Plus le code est ancien et long, plus le vin est fin et raffiné.



Malheureusement, tout n'est pas si romantique et mignon: plein de bugs, avec une abondance de failles de sécurité, toute cette dette technique devient chaque jour plus dangereuse. Au fil du temps, tous les systèmes se transforment en tas pourris à demi-vie, négligés et partiellement non soutenus. Ils sont embellis et dotés d'un esprit de noblesse, mais en réalité ce sont des momies qui n'attendent que d'être fourrées maladroitement, puis leurs furoncles purulentes et antédiluviens vont exploser et inonder votre application de leur beau botulisme chevronné.



Hmm ... dégoûtant. Mais qu'en est-il de la norme C?



Le problème que j'ai remarqué pendant mon mandat (incroyablement court) en tant que participant à une réunion est que nous mettons la compatibilité descendante au premier plan. Pour ceux qui migrent même vers C aujourd'hui, nous nous accrochons aux anciennes applications et à leurs cas d'utilisation et nous nous privons de l'opportunité d'améliorer la sûreté, la sécurité ou l'art du code C. , il peut les désactiver. Ces avertissements, et non des erreurs, ne sont pas pour rien: une machine C abstraite ne nécessite paspour faire des diagnostics, ISO C permet d'accepter un tel code dans des modes d'assemblage stricts. Et cela aiderait le monde entier à rompre avec les API qui déclarent ouvertement que «changer le contenu que nous vous fournissons est un comportement indéfini».



Cependant, nous avons changé d'avis au sujet de ce document après que la raison a été donnée comme «nous ne pouvons pas introduire de nouveaux avertissements».



L'argument contre la proposition était: "Il y a tellement de code écrit qui se cassera si nous changeons ces signatures." Ceci, encore une fois, limite les changements aux avertissements en termes de comportement de rupture (rappelez-vous, les conversions implicites qui suppriment les qualificatifs - même_Atomic- sont entièrement valides selon ISO C, même s'ils enfreignent les restrictions). Si tel était le cas, chaque auteur de compilateur introduirait quelque chose comme Ages in Rust, For Warnings Only, pour donner aux gens une référence "stable" pour les tests. Cette proposition n'est pas nouvelle: j'ai lu des documents similaires des ingénieurs de Coverity sur la génération de nouvelles alertes et la façon dont les utilisateurs y réagissent. Il est difficile de gérer la "confiance" des développeurs sur les nouveaux avertissements et autres choses. Il faut beaucoup de temps pour convaincre les gens de leur utilité. Même John Carmack a dû travailler dur pour obtenir le bon ensemble d'avertissements et d'erreurs de ses outils d'analyse statique en fonction de son développement, avant de conclure qu'il était «irresponsable de ne pas utiliser cela» .



Et pourtant, nous, le Comité, n'avons pas accepté d'ajouter constdes fonctions à valeur ajoutée aux quatre fonctions, car cela ajouterait des avertissements au code potentiellement dangereux. Nous nous sommes opposés à la désapprobation de l'ancienne syntaxe K&R, malgré des preuves solides d'oubli innocents et de vulnérabilités graves lors du passage des mauvais types. Nous avons presque ajouté un comportement indéfini au préprocesseur, juste pour le faire tomber, mais pour que l'implémentation C "se comporte comme elle le devrait". En raison de la rétrocompatibilité, nous marchons toujours sur le bord pour éviter de faire des erreurs évidentes. Et ceci, cher lecteur, m'effraie le plus sur l'avenir de S.



La norme C ne vous protège pas



Ne vous y trompez pas: peu importe ce que les programmeurs vous disent ou ce qu'ils vous chuchotent. Le comité directeur du langage C est très clair. Nous n'ajouterons pas de nouveaux avertissements à votre ancien code, même si ce code pourrait être dangereux. Nous ne vous empêcherons pas de faire des erreurs, car cela peut saper l'idée du fonctionnement de votre ancien code, ce qui est faux. Nous n'aiderons pas les débutants à écrire un meilleur code C. Nous n'exigerons pas que votre ancien code soit conforme à une norme. Chaque nouvelle fonctionnalité sera facultative car nous ne pouvons pas imaginer obliger les auteurs de compilateurs à s'en tenir à un standard plus élevé ou à attendre plus de nos développeurs de bibliothèques standard.



Nous allons laisser le compilateur vous mentir. Nous mentirons à votre code. Et quand tout va mal - il y aura une erreur, "Oh, une sorte de poubelle s'est produite", il y aura une fuite de données - nous secouerons solennellement la tête. Nous partagerons nos idées et prierons pour vous et dirons: "Eh bien, quelle honte." En effet, dommage ...



Peut-être qu'un jour nous y remédierons, cher lecteur.



All Articles