5 points par GN⁺ 2025-01-24 | 4 commentaires | Partager sur WhatsApp
  • Alors qu’EdgeDB déplaçait les E/S réseau de Python vers Rust, de nouveaux tests de HTTP fetch basés sur reqwest semblaient se bloquer uniquement sur la CI ARM64, mais il s’agissait en réalité d’un crash
  • L’analyse du core dump a montré que le point problématique n’était pas le nouveau code HTTP, mais l’intérieur de getenv() dans libc : la fonction parcourait le tableau des variables d’environnement et a échoué en tentant de lire le pointeur invalide 0x220
  • Un autre thread définissait SSL_CERT_FILE et SSL_CERT_DIR via le chemin openssl-probe, ce qui a amené setenv() à réallouer environ; en parallèle, le chemin de gestion d’erreur de Python appelait getenv(), créant une condition de concurrence
  • Le code Rust ne contenait pas d’unsafe explicite, mais pendant que std::env::set_var() modifiait l’environnement global, les autres runtimes ou les appels directs à libc n’étaient pas synchronisés par le verrou interne de Rust
  • La solution a consisté, sous Linux, à passer à rustls au lieu du backend rust-native-tls/openssl de reqwest; Rust 2024 edition et glibc évoluent aussi dans un sens qui réduit ce type de problème

Un crash qui ne se révélait que sur la CI ARM64

  • EdgeDB était en train de porter une grande partie de son code d’E/S réseau de Python vers Rust, en développant une nouvelle fonctionnalité de HTTP fetch
  • La bibliothèque client HTTP utilisée était reqwest, et la fonctionnalité passait en local ainsi que sur les runners CI x86_64, mais échouait par intermittence sur les runners CI ARM64
  • Au début, le runner de tests semblait se bloquer indéfiniment : dans les logs de CI, un test restait en cours d’exécution sans erreur jusqu’à expirer plusieurs heures plus tard
  • La première hypothèse concernait une différence de modèle mémoire entre Intel et ARM64
    • Intel a un modèle mémoire relativement strict, avec un ordre global des écritures mémoire sur lequel tous les processeurs s’accordent
    • ARM a un modèle mémoire à ordre plus faible, où les écritures peuvent apparaître dans des ordres différents selon les threads

Suivre le core dump dans un environnement CI Docker

  • La machine de CI nocturne tournait sur Amazon AWS, ce qui permettait de se connecter en tant que véritable utilisateur root hors du conteneur et de consulter dmesg ainsi que les journaux système
  • Le PID qui semblait bloqué a été recherché à l’intérieur et à l’extérieur du conteneur, mais le processus n’existait pas : cela a révélé qu’il s’agissait d’un crash, et non d’un deadlock
  • Comme un conteneur Docker est un espace de noms de processus, le core dump a été transmis à l’hôte Docker, et journalctl a permis de confirmer un core dump du processus python3
  • À la première ouverture du core avec gdb, la backtrace était inutilisable faute de fichiers .so provenant de l’intérieur du conteneur
  • Après avoir copié /lib, /usr, etc. depuis le conteneur et configuré solib-absolute-prefix dans gdb, le point de crash a été identifié comme getenv() dans libc.so.6

Le pointeur de variable d’environnement corrompu lu par getenv()

  • La backtrace complète suivait le chemin getenv()__dcigettext()strerror_r()strerror()PyErr_SetFromErrnoWithFilenameObjects()
  • Ce n’est pas le nouveau code HTTP qui a directement crashé : Python créait une exception fondée sur errno, puis passait par un chemin lié à gettext qui appelait getenv()
  • L’implémentation de getenv() dans GLIBC 2.17 parcourt l’environ POSIX comme une liste de char ** et inspecte les pointeurs vers les chaînes de variables d’environnement jusqu’au dernier pointeur NULL
  • D’après le désassemblage et l’état des registres, getenv() a crashé en tentant de lire un octet à l’adresse x19 = 0x220
    • 0x220 était manifestement une adresse mémoire invalide
    • En inspectant environ lui-même, la liste courante des variables d’environnement paraissait cohérente

Cause : une condition de concurrence entre setenv() et getenv()

  • setenv() n’est pas une fonction sûre à appeler dans un environnement multithread, et les crashes étranges dans getenv() de libc liés à ce problème ont été redécouverts à plusieurs reprises
  • En comparant le désassemblage avec le code C, x20 correspondait au pointeur ep qui parcourt le tableau environ
  • Au moment du crash, x20 valait 0x248b5000, tandis que l’environ courant valait 0x28655750, environ 60 Mo plus loin
  • En comparant la mémoire autour de l’ancien tableau d’environnement avec l’environ courant, la dernière différence apparaissait sur les entrées SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt et SSL_CERT_DIR=/etc/ssl/certs
  • Il était possible d’en déduire qu’un autre thread avait déplacé environ pendant un appel à setenv(), tandis que getenv() continuait à lire l’ancien tableau d’environnement, une situation de use-after-free

Le lien avec openssl-probe et le backend TLS

  • Un ancien ticket lié à rust-native-tls a fourni un indice : openssl-probe définit les variables d’environnement SSL_CERT_FILE et SSL_CERT_DIR pour trouver les certificats système
  • Sous Linux, ce chemin est appelé lorsque l’on utilise le backend openssl de rust-native-tls
  • Le code openssl-probe en cause définit les deux variables d’environnement avec env::set_var(), sans unsafe explicite
    • SSL_CERT_FILE
    • SSL_CERT_DIR
  • Cette combinaison a fait qu’un code Rust sans unsafe interagissait mal avec l’usage de libc dans le même processus, provoquant un crash

Pourquoi cela s’est reproduit sur ARM64 Linux

  • Ce crash se produit lorsque setenv() déplace le tableau d’environnement via realloc au moment précis où un autre thread appelle getenv()
  • Plusieurs conditions devaient être réunies pour le reproduire
    • Le nombre de variables d’environnement devait être tel qu’il déclenche un realloc
    • Un échec d’E/S sans lien direct devait être capturé par asyncio
    • Le chemin de gestion d’erreur de Python devait appeler getenv() exactement au même moment pour obtenir la variable d’environnement LANGUAGE
  • La valeur erronée 0x220 était proche de l’ancienne taille de l’environnement en mots de 64 bits
    • 0x220 / 8 = 68
    • Cette valeur avait écrasé l’emplacement du NULL final de l’ancien bloc d’environnement, et semblait être une valeur utilisée par le malloc système pour indiquer la taille d’un bloc libéré
  • Comme de nombreuses conditions préalables étaient nécessaires, le fait même que le problème soit assez reproductible sur une seule plateforme relevait de la chance

Les indices observés dans le désassemblage ARM64

  • Une confusion venait du fait que, dans le désassemblage de getenv(), le point où x20 changeait n’était pas évident
  • La clé était le mode d’adressage pré-indexé d’AArch64
  • ldr x19, [x20, #8]! fonctionne ainsi
    • x19 = *(x20 + 8)
    • x20 = x20 + 8
  • À cause de ce mode d’adressage, x20 parcourait bien le tableau de pointeurs des variables d’environnement, même s’il n’était pas explicitement écrit à gauche

Correctif appliqué et évolutions des projets concernés

  • La décision finale a été de migrer, sous Linux, vers rustls au lieu du backend rust-native-tls/openssl de reqwest
  • Le choix initial du backend TLS natif visait à éviter d’embarquer deux moteurs TLS pendant le portage du code Python vers Rust
  • Après ce problème, embarquer temporairement deux moteurs TLS a été jugé acceptable
  • Une autre solution aurait consisté à effectuer le premier appel à try_init_ssl_cert_env_vars() en tenant le GIL de Python
    • Rust possède un verrou interne qui empêche les courses entre morceaux de code Rust lisant et écrivant l’environnement
    • Mais cela ne bloque pas les cas où du code dans d’autres langages utilise directement libc
    • Tenir le GIL permettrait au moins d’éviter la concurrence avec les threads Python
  • Le projet Rust avait déjà identifié ce problème et prévoit de rendre les fonctions de modification de l’environnement unsafe dans l’édition 2024
  • Le projet glibc a aussi récemment ajouté une modification qui améliore la thread-safety de getenv() en évitant realloc et en laissant fuir les anciens tableaux d’environnement

4 commentaires

 
carnoxen 2025-01-24

setenv n’est pas thread-safe, et le C ne veut pas corriger cela

La fonction setenv fait encore des siennes.

 
y15un 2025-01-24

J’écrirais le titre ainsi : « L’absence de sûreté des threads dans la stdlib C, un échec que même Rust, pourtant sûr, ne peut pas sauver ». :)

 
halfenif 2025-01-24

J’ai bien compris avec certitude.

 
GN⁺ 2025-01-24
Avis de Hacker News
  • Le point le plus important ici, c’est que dans la prochaine édition de Rust, les fonctions de définition des variables d’environnement deviendront unsafe
    Avec un peu de chance, cela aura aussi des répercussions sur les crates qui provoquent ce type de crash ; entre-temps, une issue a été ouverte upstream : https://github.com/alexcrichton/openssl-probe/issues/30

    • Mais le problème de fond, à savoir qu’on ne peut pas appeler getenv et setenv ou unsetenv en toute sécurité depuis des threads différents, n’est pas réellement corrigé
      La seule solution fiable semble être de modifier ces fonctions pour qu’elles prennent obligatoirement un mutex
    • Le jugement de l’auteur de la bibliothèque — « de nos jours, la meilleure solution à ce problème est d’utiliser une bibliothèque comme rustls et d’arrêter d’utiliser cette crate » — paraît raisonnable, et c’est plutôt rassurant
      Malheureusement, l’écosystème n’en est pas là : https://github.com/seanmonstar/reqwest/blob/master/Cargo.tom...
    • Les gens sont entraînés à ignorer des blocs et des préfixes comme ____UNSAFE_payattention__nevermindthatthisappears50timesinthisfile___
      C’est similaire dans les frameworks web : Vue a la directive v-html et React a dangerouslySetInnerHTML ; sur ce point, je pense que Vue est clairement meilleur
  • set_var et remove_var de la bibliothèque standard Rust exigeront correctement un bloc unsafe {} dans la prochaine édition, l’édition 2024
    La documentation mentionne désormais aussi les problèmes de sûreté, mais rendre ces fonctions safe dès le départ était une erreur, une erreur que d’autres langages de plus haut niveau ont également commise
    https://doc.rust-lang.org/stable/std/env/fn.set_var.html
    glibc dispose d’un patch qui rend getenv sûr dans davantage de cas où l’environnement est modifié, mais en C on peut toujours accéder directement à environ, donc cela ne pourra jamais être totalement sûr dans les situations où des modifications se produisent : https://github.com/bminor/glibc/commit/7a61e7f557a97ab597d6f...

    • Il est surprenant que glibc conserve désormais les anciennes versions et adopte une politique de redimensionnement exponentiel
      Il en résulte une fuite mémoire de taille constante amortie pour chaque variable d’environnement active, mais les variables elles-mêmes présentent déjà ce type de fuite, en plus dépendante de leur longueur, et cela inclut même des valeurs qui ne sont plus utilisées
      Il doit certainement exister des cas d’usage pathologiques où, même dans des programmes corrects vis-à-vis de l’API, la mémoire augmente indéfiniment à cause de cela
      C’est intéressant, mais un peu dérangeant : pour corriger des programmes qui enfreignent les règles en utilisant l’API depuis plusieurs threads, on semble introduire dans les programmes qui respectent l’API un bug de croissance mémoire illimitée. Cela donne une impression de pragmatisme plutôt que de dogmatisme
    • Si l’implémentation de la bibliothèque standard peut gérer la synchronisation, on peut se demander pourquoi il faudrait exiger unsafe
  • Même si les mainteneurs de la bibliothèque standard C s’opposent à rendre setenv sûr en multithread, il faudrait au minimum définir une nouvelle API thread-safe, que ce soit dans POSIX ou en créant d’abord un standard de fait que POSIX adopterait ensuite
    Si le temps passé à expliquer pourquoi on ne peut rien faire avait été consacré à corriger ce problème, il aurait été possible de remplacer l’ancien setenv et de le déprécier puis de le supprimer dans de nombreux projets logiciels
    Le fait que glibc apporte des changements visant à faire quasiment disparaître ce problème rend peu convaincante l’affirmation du mainteneur de Musl selon laquelle il serait impossible de le corriger dans Musl

    • Le plus gros problème n’est pas l’absence d’API thread-safe, mais l’existence de extern char **environ;
      Tant que environ est publiquement accessible, rien ne garantit même que setenv et getenv soient utilisés, car ils ne sont pas obligatoires
      Si l’on pouvait supprimer environ, rendre setenv et getenv thread-safe serait assez simple. Si l’on ne peut pas le supprimer, c’est impossible ; on peut toutefois soutenir que rendre setenv et getenv thread-safe resterait une amélioration, même si ce n’est pas une solution complète
    • Toutes les fonctions exec() qui ne prennent pas l’environnement en argument ou qui recherchent dans PATH pour trouver l’exécutable devront probablement aussi prendre un verrou
    • Je ne suis pas convaincu d’en savoir plus que les experts qui ont conclu qu’on ne pouvait pas corriger cela de manière rétrocompatible
  • Sous Linux, tomber sur des bugs liés aux variables d’environnement ressemble à une sorte de rite de passage, alors que sur les autres Unix, curieusement, c’est généralement moins problématique.
    Linus et le noyau corrigent les bugs POSIX de façon pragmatique, en faisant en sorte qu’ils ne se manifestent pas vraiment, tandis que glibc reste à la traîne alors que cela fait des décennies que des gens essaient d’atténuer ne serait-ce qu’un peu le problème, ce qui est assez amusant.
    Il est vrai qu’il existe toutes sortes de casse-têtes comme TZ, mais si getenv_r() avait été fourni, synchronisé avec setenv(), et si l’utilisation de getenv() avait simplement déclenché un avertissement à la compilation et à l’édition de liens, une grande partie des problèmes aurait disparu.
    On aurait même pu aller plus loin avec une approche copie à l’écriture (COW) où les pointeurs d’environnement restent en lecture seule.
    À la place, le problème a été refilé à chaque application, ce qui est une grosse erreur, car les auteurs d’applications peuvent difficilement savoir ce que font leurs dépendances. C’était aussi la situation dans laquelle je me suis retrouvé il y a longtemps, et à l’époque le fournisseur de la bibliothèque propriétaire m’avait dit d’arrêter d’utiliser ce clone Unix jouet qu’était Linux.

    • Je ne sais pas d’où vient l’idée qu’« il y a des bugs liés aux variables d’environnement sous Linux et moins sur les autres Unix ».
      Le problème n’est pas l’implémentation, mais l’API elle-même. setenv(), unsetenv(), putenv(), et surtout environ, sont intrinsèquement dangereux dans les programmes multithread.
      Même getenv_r() ne peut pas tout sauver. Pendant qu’un thread copie l’ancienne valeur d’une variable d’environnement dans le tampon fourni, un autre thread peut appeler setenv().
      Bien sûr, getenv_r() corrige le cas où, après avoir reçu une valeur via getenv(), un autre thread appelle setenv() et invalide cette mémoire, mais il n’existe aucun moyen d’empêcher les autres appels qui cassent l’API.
      La libc peut atténuer une partie du problème en prenant un mutex dans getenv()/setenv()/putenv()/unsetenv(), mais elle n’a toujours aucun moyen de garantir que la valeur renvoyée par getenv() restera valide assez longtemps pour que le code appelant l’utilise.
      Il n’y a pas non plus de bonne façon de rendre sûr l’accès direct à environ. On pourrait rendre environ local à chaque thread, mais alors la vision de l’environnement pourrait diverger définitivement d’un thread à l’autre, et les résultats d’un appel à getenv_r() pourraient différer de ceux d’une consultation directe de environ.
      Ici, préserver la compatibilité descendante est vraiment difficile, et le simple fait d’ajouter un mutex pour protéger ces fonctions pourrait déjà modifier la sémantique de programmes existants et les casser.
  • Il y avait déjà eu un article disant que setenv était épouvantable : https://www.evanjones.ca/setenv-is-not-thread-safe.html
    Il y avait aussi eu une discussion, et dès le premier commentaire il était question de problèmes causés en Rust : https://news.ycombinator.com/item?id=38342642

    • C’est déjà bien connu.
      Ici, la plupart des autres problèmes semblent relever de l’environnement de développement. Les tests étaient exécutés avec Docker sur une machine distante dans un datacenter Amazon, et cette machine n’arrivait pas à signaler le crash du processus.
      En plus, il n’y avait pas assez d’informations de symboles de débogage dans le conteneur pour obtenir une trace de pile. Si une trace propre avait été obtenue dès le premier échec, cela aurait été immédiatement évident.
      Je me demande surtout pourquoi utiliser setenv au départ.
  • Cette discussion me rappelle le mouvement 12-factor app, auquel plusieurs anciens collègues croyaient énormément. L’un de ces « factors » était que la configuration de l’application devait se faire via des variables d’environnement
    J’ai toujours trouvé ça un peu idiot, parce que ce mode de configuration revient à mettre des valeurs de type chaîne dans un espace de noms plat, comme dans un panier
    Je vois aussi les dangers de getenv()/setenv()/environ comme un argument fort pour ne pas utiliser les variables d’environnement pour la configuration
    Bien sûr, il n’existe pas toujours une excellente alternative bien prise en charge. Je préfère les fichiers de configuration, et on peut aussi utiliser des configurations modèles où l’on ne renseigne que les valeurs de développement, de staging et de production. En général, malgré ses défauts et ses pièges, j’utilise YAML ; il existe peut-être de meilleurs formats de fichier de configuration, mais je considère que YAML est nettement préférable aux variables d’environnement

    • Il existe beaucoup d’hostilité marquée envers Windows et Microsoft, mais avec le temps, leur conception d’API se trouve assez souvent justifiée
      Dans NT, les variables d’environnement peuvent être typées et modélisées, et il y a aussi le registre, une base de données de configuration avec espaces de noms. C’est verbeux et étrange, certes
      En plus, MSVC fournit des versions thread-safe de presque toutes les fonctions de la bibliothèque standard
      J’entends souvent de nouveaux développeurs C/C++ déplorer le manque de compatibilité POSIX de MSVC, mais ils ne semblent pas réfléchir très profondément à ce que cela veut dire en pratique. Cela ressemble plutôt au souhait d’être compatible avec des programmes C écrits dans les années 1990
    • J’ai des préoccupations similaires au sujet des variables d’environnement. Je n’aime pas le fait qu’on puisse les lire de n’importe où
      Cela nuit à la capacité de déduire le comportement à partir de la seule signature d’une fonction, et rend impures beaucoup de fonctions qui auraient pu être pures
      S’il existait une fonctionnalité de langage permettant de marquer une application pour que, dans n’importe quel processus, les variables d’environnement ne puissent pas être utilisées et ne puissent être lues qu’une seule fois, en une seule opération globale et non variable par variable, je pense que je l’utiliserais partout
    • getenv() lui-même ne pose aucun problème ; le problème, c’est setenv()
      En théorie, l’environnement est défini avant le lancement de cette mystérieuse application, donc on ne devrait pas avoir besoin de l’utiliser
      Mais un espace de noms plat, des valeurs sous forme de chaînes, et un espace global libre et partagé par tout le monde sans savoir quelles bibliothèques ni quels modules s’y invitent, ce n’est pas une bonne idée même sans les problèmes de sûreté de setenv()
    • Il faudrait ajouter à « 12-factor app » une annexe disant que, tant que le processus est vivant, l’environnement doit être traité comme étant en lecture seule
      La plupart des problèmes évoqués ici semblent venir de l’abus consistant à vouloir utiliser l’environnement comme un stockage clé-valeur pour de l’état global mutable. Je ne vois pas pourquoi on voudrait faire ça
      La JVM traite en pratique l’environnement comme immuable, et il est possible que des entreprises utilisant Scala et Java, comme SoundCloud, aient influencé le mouvement 12-factor app. Je n’ai jamais rencontré de cas où l’environnement changeait ou provoquait des problèmes de threading
      Même si l’environnement change, la copie immuable créée au démarrage de la JVM reste telle quelle, et le code qui interagit avec l’environnement via les API Java ordinaires ne voit pas cette modification
      Le problème des fichiers de configuration, c’est que le parsing est propre à chaque processus. C’est pour cela que Linux/Unix est si désordonné. Chaque outil a ses propres conventions et mécanismes de configuration, sans standard
      Dans l’écosystème Docker, peu importe ce que l’on fait à l’intérieur du conteneur : l’interface avec l’extérieur consiste soit à monter des volumes et à suivre le système de configuration complexe de chaque application, soit tout simplement à utiliser des variables d’environnement
      Aujourd’hui, la plupart des logiciels modernes exécutés avec Docker sont assez compatibles avec Docker pour que leur comportement puisse être entièrement contrôlé par l’environnement, et dans beaucoup de cas c’est suffisant
      Avec Docker Compose ou Kubernetes, on se retrouve avec une liste de variables d’environnement définissant le lancement du processus dans un fichier YAML, ce qui donne dans une certaine mesure la structure souhaitée. Je n’aime pas YAML, mais ça fonctionne suffisamment bien ; les problèmes de syntaxe ont de bonnes chances de gâcher une journée, mais les alternatives ne sont pas exemptes de problèmes non plus
    • En réalité, c’est un problème distinct. Si l’on lit les variables d’environnement comme configuration puis qu’on n’y touche plus, c’est parfaitement sûr
      Moi aussi, j’utilise le style 12-factor app, mais une fois les variables d’environnement et les données entrées dans l’application, je les valide et les stocke. Après ça, il n’y a plus aucun problème
  • C’est un excellent article qui creuse un bug difficile à repérer
    Il y avait de tout : bug intermittent, spécificité d’architecture, bug caché dans une dépendance, Rust, le GIL de Python, et même gettext
    Ces rapports de résolution de problème détaillés sont ce qui se rapproche le plus du fait de l’avoir vécu soi-même. Dans une situation où une dépendance utilise ça et où l’on ne pouvait pas le savoir, il est difficile de dire facilement « il suffisait de ne pas utiliser X »

  • Ils disent que « les machines de CI nocturne tournent sur Amazon AWS et ont l’avantage de pouvoir utiliser un vrai utilisateur root, pas un conteneur », tout en disant aussi que « les fichiers nécessaires n’existent pas hors du conteneur, et le conteneur est tellement minimal qu’il n’est pas facile d’y installer gdb »
    Les gens ont-ils désormais perdu la capacité de compiler et déboguer en local, sans cloud ni conteneurs ?

    • Oui. C’est choquant de voir à quel point le SaaS cloud a déformé la compréhension des gens
      Pour faire des choses très triviales, il faut désormais toutes sortes de complexités cloud et de couches de déploiement. On a inversé à 100 % la révolution du PC pour revenir à l’époque lourde et coûteuse du mainframe computing
      La raison, c’est que l’argent est dans le cloud, et que le cloud est un DRM. Si vous y mettez le logiciel, vous pouvez facturer un abonnement, il est impossible de le contourner, et vous conservez indéfiniment une dépendance totale. Souvent, les utilisateurs ne peuvent même pas récupérer leurs propres données
      Cela permet aussi de faire facilement de l’analytique en temps réel pour optimiser le produit
      L’architecture informatique est en aval du modèle économique. Si le mainframe a d’abord disparu, c’est parce qu’il n’y avait pas Internet et que les PC étaient moins chers, mais aussi parce que les fournisseurs ont perdu une grande partie de leur pouvoir d’enfermement
      Désormais, il existe un moyen de ressusciter un modèle bien plus rentable. La liberté gênante des utilisateurs a disparu, et franchement, quand les utilisateurs obtiennent ce genre de liberté, ils finissent souvent par ne pas payer, ce qui rend difficile l’existence d’entreprises de logiciels de qualité
    • C’est le genre de problème de corruption mémoire aléatoire qui ne se déclenche que sur ARM
      Il est très probable qu’ils n’aient pas pu reproduire le crash en local. Les machines des développeurs étaient probablement majoritairement en x86, où le crash ne se produisait pas
      Ils auraient dû mieux gérer le crash, mais ils semblent eux-mêmes conscients du problème, et ce n’est pas le point central traité ici
    • Évidemment qu’ils n’ont pas perdu cette capacité, mais le crash ne se produisait pas sur nos machines
    • Comment déboguer en local si l’on n’a probablement pas d’appareil capable d’exécuter l’architecture problématique ? De toute façon, il est beaucoup plus rapide de déboguer dans l’environnement réel où l’échec se produit
  • L’état global mutable, c’est le mal. Entre amis, on ne laisse pas ses amis utiliser de l’état global mutable
    Je déteste les variables d’environnement. C’est la « façon Linux » de faire, mais je les évite comme la peste. Je recommande vivement
    libc est épouvantable, et le monde devrait passer à autre chose

    • Les variables d’environnement ne posent pas de problème si on les traite comme en lecture seule au sein du processus
    • Si « l’état global mutable est le mal », alors il faut aussi jeter le CPU et la RAM
    • Je me demande quelle alternative est proposée
      Le problème, ce n’est ni Linux, ni l’état global mutable ou les ressources, ni libc
      Le problème, c’est qu’au travail on ne nous donne pas le temps de faire les choses correctement. Par exemple, pour repérer le problème avec GDB avant qu’il n’éclate, il faut que votre supérieur vous laisse le temps de déboguer obstinément le code et tout ce qu’il touche, puis de remonter la piste
      Il y a trop d’argent investi dans du code à moitié cuit. C’est triste, mais vrai
    • libc a propulsé le monde dans l’ère de l’information
    • Je me demande quelle est l’alternative préférée
  • Il y a tellement de problèmes de ce genre qu’au final j’ai patché getenv / setenv / putenv avec LD_PRELOAD

    • Est-ce que ça a été fait avec une implémentation corrigée qui fuit l’environnement, comme celle qui vient d’arriver dans glibc ?