Les risques de la transition vers `time_t` 64 bits
(blogs.gentoo.org)- Sur les systèmes glibc 32 bits, la récupération de l’heure courante ou les appels à
stat()peuvent échouer après 2038, ce qui impose à Gentoo une voie de migration sûre vers untime_t64 bits - Le support time64 de glibc doit être utilisé avec le Large File Support (LFS) et, en environnement 32 bits, l’ancien ABI, l’ABI LFS et l’ABI LFS+time64 coexistent
- Dès que
time_tapparaît dans une API, une structure ou des arguments de fonction, le changement de largeur du type provoque une rupture d’ABI ; mélanger des binaires time32 et time64 peut alors entraîner des dysfonctionnements à l’exécution et des risques de sécurité - En tant que distribution basée sur les sources, Gentoo peut se retrouver avec un système partiellement migré à cause d’échecs ou de dépendances circulaires pendant la reconstruction de
@world - Depuis la correction du 2024-09-30, il apparaît qu’un simple changement de libdir ne suffit plus, et qu’un marquage time64 englobant aussi le chargeur dynamique et plusieurs toolchains de langage devient la contrainte centrale
Le problème de l’an 2038 et l’ampleur de la transition time64
- Les applications 32 bits qui utilisent un
time_t32 bits peuvent, en 2038, recevoir l’erreur-1au lieu de l’heure courante, ou ne plus pouvoir exécuterstat()sur des fichiers - La direction générale de la transition consiste à remplacer
time_tpar un type 64 bits- musl a déjà effectué cette transition
- glibc la prend en charge en option
- certaines distributions comme Debian l’ont déjà adoptée
- Les distributions basées sur les sources comme Gentoo obligent l’utilisateur à reconstruire lui-même le système, ce qui impose de réduire au minimum la durée pendant laquelle les paquets restent dans des états ABI différents
- Le risque principal est que le changement de taille de
time_tcasse l’ABI- si
time_tfigure dans l’API d’une bibliothèque, tout le code lié à cette bibliothèque doit utiliser la même largeur de type - une migration partielle vers time64 n’est pas sûre
- si
LFS et les trois sous-ABI 32 bits
- Les architectures 32 bits avaient déjà, auparavant, des problèmes de largeur de type liés aux fichiers
off_tsert aux offsets de fichierino_tsert aux numéros d’inode- à l’origine, ils étaient codés sur 32 bits, ce qui posait problème pour les fichiers de plus de 2 GiB ou les numéros d’inode dépassant la plage 32 bits
- Pour y remédier, le Large File Support (LFS) a été introduit
off_tetino_tpassent à des variantes 64 bits- dans glibc, cela reste encore aujourd’hui optionnel
- beaucoup de paquets activent LFS en amont et gèrent la rupture d’ABI, mais le problème n’est pas totalement résolu
- Le support time64 de glibc exige l’usage de LFS, ce qui revient à traiter ensemble les problèmes de taille de fichier et de temps
- Sur les systèmes 32 bits, il existe trois sous-ABI
- ABI historique : types 32 bits
- LFS :
off_t64 bits,ino_t64 bits,time_t32 bits - time64 : LFS +
time_t64 bits
- Une même build de glibc reste compatible avec ces trois variantes, mais les bibliothèques qui utilisent ces types dans leur API ne peuvent pas mélanger ces trois variantes entre elles
Comment le changement d’ABI casse concrètement les choses
- Quand
time_tpasse de 32 à 64 bits, la disposition des structures change- dans une structure d’exemple avec
int a,time_t b,int cdans cet ordre, l’offset decdiffère selon quetime_test sur 32 ou 64 bits - si l’on mélange des binaires time32 et time64, on peut lire ou écrire les mauvais champs, voire accéder hors limites
- dans une structure d’exemple avec
- La taille de
struct statchange elle aussi selon l’ABI- valeur par défaut de glibc sur x86 32 bits : 88 octets
- LFS : 96 octets
- LFS + time64 : 108 octets
- Même sans structure, des problèmes apparaissent dans les arguments de fonction
- sur x86, les arguments de fonction sont passés via la pile
- si l’un des arguments est un
time_t, la position sur la pile des arguments suivants change
- Dans l’expérience d’exemple, un programme time32 voit ses valeurs corrompues lorsqu’il est lié à une bibliothèque reconstruite en time64
- la sortie d’origine est
a = 1, une valeur de temps correcte, puisc = 3 - si seule la bibliothèque est reconstruite avec
-D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64,betcsont interprétés de travers
- la sortie d’origine est
- À l’heure actuelle, il n’existe pas de mécanisme de protection réellement efficace contre ce mélange d’ABI, ce qui peut provoquer des ruptures à l’exécution et des problèmes de sécurité
Pourquoi la transition est plus difficile pour Gentoo
- Les distributions binaires reconstruisent tous les paquets avant que l’utilisateur effectue la mise à niveau, selon une étape relativement atomique
- des problèmes peuvent subsister avec des dépôts tiers ou des programmes compilés localement, mais l’ensemble du processus reste relativement sûr
- Gentoo doit modifier l’ABI sur place pendant la reconstruction de
@world- entre la reconstruction de deux paquets, des ABI incompatibles peuvent se retrouver mélangés
- si certaines reconstructions échouent, le système peut rester dans un état partiellement migré
- des dépendances circulaires peuvent casser les outils de build lorsqu’on reconstruit les paquets requis, rendant la suite de la migration impossible
Les pistes de mitigation à l’étude
- Trois directions sont discutées
- changer le tuple de plateforme
CHOSTpour distinguer le nouvel ABI de l’ABI 32 bits existant - changer le libdir du nouvel ABI afin d’installer les bibliothèques reconstruites séparément des anciennes
- introduire une distinction d’ABI au niveau binaire pour empêcher l’édition de liens entre binaires de sous-ABI différents
- changer le tuple de plateforme
- Les trois approches peuvent être implémentées de manière assez indépendante, même si certaines peuvent dépendre des autres
- Les chaînes d’exemple dans l’article ne correspondent pas nécessairement aux chaînes finales de la solution retenue
Distinguer l’ABI via CHOST
- Le tuple de plateforme identifie la plateforme cible de la toolchain et, dans Gentoo, sert aussi à distinguer proprement les ABI pour le support multilib
- Le tuple se compose de quatre parties : architecture, vendor, système d’exploitation et libc
- exemple :
i386-pc-linux-gnu - exemple :
i686-pc-linux-gnu - exemple :
i686-unknown-linux-gnu
- exemple :
- Lors de l’introduction d’un nouvel ABI, on a déjà utilisé soit une modification du champ vendor, soit un suffixe ajouté au champ libc
- pour l’ABI ARM hardfloat, on a vu par le passé des formes comme
armv7a-hardfloat-linux-gnueabietarmv7a-unknown-linux-gnueabihf
- pour l’ABI ARM hardfloat, on a vu par le passé des formes comme
- Des options comparables existent pour l’ABI time64
i686-gentoo_t64-linux-gnui686-pc-linux-gnut64armv7a-gentoo_t64-linux-gnueabihfarmv7a-unknown-linux-gnueabihft64
- Le changement de tuple ne semble pas nécessiter un grand nombre de patchs
- la GNU toolchain et le système de build GNU ignorent ce qui suit
gnudans le champ libc - Clang aurait besoin d’un patch pour sélectionner automatiquement le bon ABI selon le tuple
- la GNU toolchain et le système de build GNU ignorent ce qui suit
Changement de libdir et preserved-libs
- Le libdir est le nom par défaut du répertoire d’installation des bibliothèques
- la valeur la plus courante est
lib - sur les architectures compatibles 64 bits, on utilise souvent
lib64par convention - l’ABI x32 sur x86 utilise
libx32, et l’ABI n32 sur MIPS utiliselib32
- la valeur la plus courante est
- Pour l’ABI 32 bits en time64, l’idée étudiée consiste à remplacer
libpar quelque chose commelibt64 - Un libdir séparé sert de mécanisme pour limiter le mélange d’ABI pendant la transition
- il réduit le risque qu’un exécutable time64 se lie par erreur à une bibliothèque time32
- il permet de conserver les bibliothèques time32 grâce à la fonctionnalité preserved-libs de Portage
- il devient aussi possible de proposer, en option, un profil multilib time32 + time64 afin de garder la compatibilité avec les applications précompilées existantes en time32
- Avec preserved-libs, les anciens exécutables continuent d’utiliser les bibliothèques time32 jusqu’à leur reconstruction, tandis que les bibliothèques reconstruites en time64 sont installées dans le nouveau libdir
- Le changement de libdir nécessite des patchs dans la toolchain
- glibc peut recevoir un traitement particulier, car le même ensemble de bibliothèques reste valable pour plusieurs sous-ABI
- un
ld.sodistinct pourrait être nécessaire pour que le champ.interpdes exécutables time64 pointe vers leld.soprévu pour time64
- Un support multilib correct exigerait aussi un tuple de plateforme propre à cet ABI
Marquer l’incompatibilité au niveau binaire
- Quand on mélange des binaires de différents ABI, l’éditeur de liens ou le chargeur dynamique devraient en principe l’empêcher
- si l’on tente de lier un programme 64 bits avec une bibliothèque 32 bits, l’éditeur de liens refuse avec
file in wrong format - le chargeur dynamique refuse lui aussi avec des erreurs comme
wrong ELF class: ELFCLASS32
- si l’on tente de lier un programme 64 bits avec une bibliothèque 32 bits, l’éditeur de liens refuse avec
- Plusieurs mécanismes sont déjà utilisés pour distinguer les ABI existants
ELFCLASS32etELFCLASS64- des identifiants de machine comme
EM_386etEM_X86_64 - le champ flags sur ARM et MIPS
- des sections d’attributs propres à certaines architectures
- time32 et time64 auraient besoin d’un mécanisme comparable, mais la solution n’est pas simple
- il ne semble pas exister de mécanisme générique réutilisable
- il faut une solution adaptée à plusieurs architectures
- l’ajout d’une nouvelle section de note ELF, avec le support correspondant dans la toolchain, apparaît comme un candidat réaliste
- Il faut aussi tenir compte du fait que les utilisateurs pourraient désactiver cette protection
- si un logiciel précompilé sans code source n’appelle pas d’API utilisant
time_t, il peut continuer à fonctionner avec les bibliothèques système - l’empêcher dans tous les cas pourrait être pire que le problème lui-même
- si un logiciel précompilé sans code source n’appelle pas d’API utilisant
- Avec un libdir distinct, il devient relativement simple de mettre en place des contrôles QA non bloquants
- on distingue les exécutables time64 via
.interp - on vérifie qu’un programme time32 ne charge pas de bibliothèque depuis
libt64 - on vérifie qu’un programme time64 ne charge pas directement de bibliothèque depuis
lib
- on distingue les exécutables time64 via
Les limites des applications 32 bits précompilées
- Indépendamment des paquets compilés depuis les sources, il existe encore sur x86 et PowerPC des applications fournies uniquement sous forme de binaires précompilés anciens
- c’est notamment le cas de logiciels propriétaires et de vieux jeux
- Elles rencontrent à la fois des problèmes de compatibilité avec les bibliothèques système et le problème de l’an 2038 lui-même
- Pour les problèmes de compatibilité, l’infrastructure multilib existante apporte déjà en partie une solution
- sur amd64, il existe déjà un agencement multilib et des mécanismes pour compiler plusieurs versions de bibliothèques afin de prendre en charge les logiciels 32 bits
- cela pourrait être étendu en distinguant
abi_x86_32etabi_x86_t64 - un nouveau profil x86 multilib pourrait prendre en charge les deux ABI
- En revanche, l’échec intrinsèque des programmes 32 bits après 2038 reste plus difficile à résoudre
- il est possible de contrôler l’heure système avec faketime
- il est aussi possible d’exécuter une VM dont l’horloge est réglée dans le passé
Correction du 2024-09-30 : le libdir seul ne suffit pas
- La conception initiale était trop optimiste, et un simple changement de libdir ne permet pas une séparation fiable
- Tous les libdir étant listés dans
ld.so.conf, on ne peut pas s’appuyer sur un chemin de libdir codé en dur dansld.so- les préfixes LLVM personnalisés ajustent déjà les chemins, et ce cas nécessite lui aussi un traitement particulier
- En conséquence, il devient plus probable que le changement de libdir doive dépendre d’une distinction d’incompatibilité binaire
- Trois objectifs de base doivent être remplis
- le chargeur dynamique doit distinguer les binaires time32 et time64
- tous les binaires sans marquage time64 explicite doivent être considérés comme time32 pour préserver la rétrocompatibilité
- tous les nouveaux binaires doivent porter un marquage time64 explicite, y compris ceux construits hors de l’environnement C, par exemple en Rust
- Cela représente un travail qui implique de patcher plusieurs toolchains dans plusieurs langages
- Gentoo aurait du mal à maintenir cela uniquement en local, et la coopération de plusieurs parties serait nécessaire
- les architectures visées sont souvent considérées comme legacy ou ne bénéficient plus d’un support suffisant
- Une autre question est de savoir si les autres toolchains produiront bien des exécutables time64 corrects
- si elles ne sont pas adaptées pour suivre
_TIME_BITScomme les programmes C, elles peuvent coder en dur une certaine largeur detime_tet se casser
- si elles ne sont pas adaptées pour suivre
- Comme tous les binaires sans marquage time64 explicite utiliseraient les bibliothèques time32, Gentoo ne pourrait plus exécuter des exécutables tiers sans patch qui ne portent pas le marquage correct
- Des objectifs plus modestes sont aussi envisagés
- injecter un RPATH dans tous les exécutables time64 pour forcer directement l’usage du libdir time64
- cette approche n’empêche pas totalement le chargeur dynamique d’utiliser des bibliothèques time32, mais elle peut faciliter la transition sans gros problèmes de compatibilité
- À l’inverse, une autre option consiste à ne pas changer durablement le libdir time64, mais à renommer temporairement le libdir time32
- on injecte un RPATH dans les programmes existants et on change le nom du libdir
- les nouvelles bibliothèques time64 sont installées dans le libdir existant
- les nouveaux programmes time64 n’ont pas de RPATH imposant les bibliothèques time32
- cela présente l’avantage de préserver la compatibilité avec d’autres distributions qui ont déjà effectué la transition
Les défis qui restent
- Si les trois solutions sont toutes implémentées, elles pourraient offrir aux systèmes Gentoo 32 bits utilisant glibc une voie de migration plus propre et relativement sûre
- Cela dit, ces solutions s’appliquent surtout aux paquets compilés depuis les sources
- Pour les applications 32 bits précompilées, le problème de l’an 2038 demeure même si la compatibilité ABI est préservée
- L’ensemble de la conception reste encore à l’état d’ébauche et peut continuer à évoluer en fonction des expérimentations, des discussions et des propositions de patchs
1 commentaires
Avis de Hacker News
Gentoo dispose de quelques options non abordées dans l’article, qui semblent avoir été omises parce que la conception du système Gentoo rendrait le travail conséquent
.soafin de refléter aussi les changements d’ABI des paquets dépendants. En général, les bibliothèques partagées incluent un numéro de version dans le nom de fichier et dans la version interne, commelibfoo.so.1.0.0, et le paquet suit ses propres ruptures d’ABI. Pour prendre en chargetime_ten 64 bits, il faudrait ajouter, pour chaque.so, un élément de version contrôlé par l’ABI de ses dépendances. Le résultat serait similaire au « recours à un autre libdir » décrit dans l’article, mais cela pourrait constituer une base réutilisable pour de futurs changements d’ABI, au prix d’une approche probablement bien plus intrusiveOn pourrait planifier la compilation de plusieurs nouveaux paquets, les construire dans un bac à sable, puis faire en sorte que les nouvelles compilations consultent d’abord le bac à sable via une union, avant de se rabattre sur le système. Une fois tout compilé, il suffirait de empaqueter les résultats et de les déplacer du bac à sable vers le système réel. Ainsi, toute la mise à jour Gentoo pourrait devenir transactionnelle, ce qui apporterait de gros avantages à d’autres égards également
ROOT, qui vaut généralement/On peut reconstruire tout
@systemet@world, les installer dans le sous-répertoire indiqué, puis synchroniser le tout en une seule fois. Si possible, il vaut mieux le faire depuis une session live ; en théorie, on peut aussi monter/en bind dans un sous-répertoire du nouvel emplacement installé, entrer dedans avec chroot, puis synchroniser vers le vrai/parenthttps://devmanual.gentoo.org/ebuild-writing/variables/#root
La manière dont Mac OS X a traité
off_tetino_tpourrait donner une piste. Les appels et structures existants ont conservé leur comportement, de nouveaux appels et types avec le suffixe64ont été ajoutés, et des macros de préprocesseur permettaient de choisir la cible réellement référencée, même si on les utilisait rarement directementÀ la place, l’OS et le SDK sont versionnés, et l’on peut indiquer au moment de la compilation la plus ancienne version de l’OS sur laquelle le binaire doit pouvoir s’exécuter. Les en-têtes sélectionnaient automatiquement les macros appropriées sur cette base, et les annotations d’API nouvelles ou obsolètes utilisaient le même mécanisme pour produire des liens faibles ou des avertissements. Au début, c’était géré par le préprocesseur, mais aujourd’hui le compilateur comprend plus finement ce qu’Apple appelle la disponibilité des API, si bien qu’une approche similaire semble possible sur d’autres plateformes
Même lorsqu’elles s’exécutent sur OS v.B, une application X déclarée comme ciblant OS v.B peut ne pas pouvoir être liée avec une application Y déclarée comme ciblant OS v.A. En réalité, cette méthode ressemble à ce que presque toutes les plateformes font déjà, et procéder autrement casserait immédiatement la compatibilité avec les binaires existants
off_t, et il n’y aura pas non plus dans les en-têtes de mécanisme choisissant de façon transparente le bon ensemble de fonctions selon la taille de type souhaitée par le programme clientPourtant, l’article souligne que
time_tpose un problème plus important queoff_t. La raison plausible est quetime_test beaucoup plus répandu.off_test un type POSIX impliqué dans un nombre relativement limité d’interfaces, tandis quetime_tappartient à l’ISO C et est utilisé un peu partout. De plus, beaucoup de code C suppose quetime_test un type entier de même largeur queint, alors que ce genre d’hypothèse est moins courant pouroff_tDebian aussi a beaucoup souffert. Certains ont peut-être fait un burn-out, et beaucoup de gens pointaient les distributions basées sur les sources en disant : « là-bas, ce sera très facile »
/usr, par exempleChaque fois que je vois des gens souffrir de ce genre de problème, je me dis que c’était vraiment une bonne chose d’avoir imposé ça lors du portage amd64 initial de FreeBSD. On pouvait définir les types de base de l’ABI, et on a décidé de regarder vers l’avenir plutôt que vers le passé.
amd64 avait une caractéristique intéressante qui a facilité ce travail. Pendant les appels de fonction, les arguments 32 bits étaient automatiquement convertis en 64 bits ; du coup, même si l’on passait un entier temporel 32 bits à une fonction qui attendait un
time_t64 bits, cela fonctionnait généralement pendant les premiers travaux sur la plateforme. On pouvait donc repousser les petites finitions à plus tard.Il existait d’autres plateformes 64 bits à l’époque, mais elles n’avaient pas de
time_t64 bits, et FreeBSD/amd64 a été, vers 2003-2005, la première de cette lignée. De mémoire, sparc64 est aussi passé à untime_t64 bits.Le plus gros problème était qu’à l’époque, tzcode n’était pas sûr en 64 bits. L’algorithme de normalisation de
struct tmtombait dans un cas dégénéré où il essayait de calculer en boucle le jour, le mois et l’année detime_t(2^62). Plutôt que de modifier lourdement tzcode, je crois qu’on avait traité comme des échecs les dates antérieures à environ 1900 ou postérieures à l’an 10000. Il est très probable que cela ait été corrigé upstream depuis longtemps.Pendant quelques années, on a joué à la taupe avec le code tiers qui mélangeait les temps 32/64 bits en traitant négligemment
int/long/time_tdans les structures de données de fichiers ou de réseau, mais dans l’ensemble ce n’était pas un gros problème. Avoir utilisé untime_t64 bits dès le premier jour a permis d’éviter la plupart des problèmes, et le faire dès le départ était facile. Linux a raté une grande occasion de faire la même chose au lancement de son port amd64/x86_64.À côté de ça, le
ino_t64 bits n’a pas été terminé à l’époque. Les numéros d’inode 32 bits étaient exposés à énormément d’endroits : structures on-disk des systèmes de fichiers, structures de répertoires UFS, etc. Quand FreeBSD/amd64 était encore une plateforme de rang inférieur, il n’y avait pas de façon réaliste de régler ça dès le départ sans bousculer fortement d’autres architectures tier-1. Le travail a été fait deux fois, mais quelqu’un d’autre a fini par le terminer, en corrigeant au passage des constantes beaucoup trop courtes, comme la longueur des chemins de mountpoints.time_t,off_tetino_t64 bits. Le problème actuel est de faire passer Linux 32 bits à untime_t64 bits.off_t, qui est en 64 bits depuis la 2.0. Les versions 32 bits de Linux conservent encore des traces de l’ancienne taille.Pour la partie indiquant que les arguments de fonction 32 bits sont automatiquement convertis en 64 bits lors de l’appel, je comprends que cela ne fonctionne que pour les arguments non signés. C’est parce qu’un chargement dans
%ediefface la partie haute de%rdi. La spécification de l’ABI SysV pour x86-64 ne dit pas que toutes les valeurs dans les registres ou sur la pile sont étendues en valeurs complètes de 64 bits, et la note sur les booléens indique aussi que seul l’octet de poids faible est significatif, ce qui suggère que c’est la règle générale.time_td’i386 en 64 bits quand amd64 est apparu, c’est assez surprenant. Je me demande si d’autres architectures 32 bits comme Motorola 68000 ou sparc32 sont aussi passées à untime_t64 bits.Sur un vieux gros système Unix 32 bits, pour gérer des dates futures, j’ai déjà remplacé les fonctions libc utilisant un
time_t32 bits signé par des équivalents entime_t32 bits non signé. Cela a permis de gagner 68 ans après 2038, et d’ici là je ne serai déjà plus là.L’inconvénient, c’est qu’on ne peut plus représenter les dates antérieures à 1970, l’epoch Unix, mais comme c’était un système de gestion d’agenda, ce n’était pas un problème. Si les dates passées sont importantes, on peut aussi déplacer l’epoch de quelques décennies ou réduire la résolution temporelle de 1 seconde à 2 secondes. Chacune de ces solutions a ses subtilités, donc cela dépend du cas d’usage.
Dans la page de manuel BSD originale de
tunefs, la section « Bugs » contenait la célèbre blague : « You can tune a file system, but you can't tune a fish. » D’après « Expert C Programming », le code source de cette page de manuel contenait, à côté de cette blague, le commentaire suivant :« Si vous retirez ceci, le démon UNIX vous poursuivra à quatre pattes à partir de maintenant et jusqu’au wrap around de
time_t. »Quand cette phrase a été écrite dans les années 70, 2038 devait certainement sembler un avenir inimaginablement lointain.
https://progforperf.github.io/Expert_C_Programming.pdf
Ce qui me frappe surtout, c’est que, même si je respecte l’effort, du point de vue utilisateur j’aurais envie de passer à une distribution non basée sur les sources comme Debian pour en finir avec ce problème.
mkfs.ext4— ou le système de fichiers utilisé — sur les partitions/et/usr, on les monte, on extrait stage3, on entre dans le chroot et on lanceemerge $all-my-packages-that-where-installed-before-mkfs.Au lieu de mettre à niveau progressivement, on peut installer une nouvelle copie de Gentoo.
S’il y a des logiciels tiers propriétaires, on peut encore rencontrer des problèmes même avec un système binaire. Des paquets first-party installés séparément comme étape indépendante peuvent aussi poser problème.
Je ne suis pas spécialiste du C, mais je pensais que les alias de types comme
off_tavaient été introduits justement pour pouvoir les changer plus tard. Or cela ne semble manifestement pas fonctionner ainsi ; je me demande si je me trompeoff_tévite généralement de devoir réécrire le code, mais il faut recompiler tout ce qui utilise ce typeoff_t, on pouvait reconstruire@worldde façon atomique, il n’y aurait pas de problème ; mais une distribution basée sur les sources ne reconstruit pas@worldatomiquement, elle reconstruit les paquets un par unOn peut alors se retrouver avec un
libc.soutilisant unoff_t64 bits, tandis quegcca été construit en supposant unoff_t32 bits, ce qui peut faire plantergcc. Des paquets nécessaires à la reconstruction de@world, commebash,coreutils,makeoubinutils, peuvent aussi se casser, et à ce stade on est bloqué. C’est pourquoi ce genre de mise à niveau demande de la prudenceoff_tse retrouve dans une structure, utilisé dans un appel de fonction ou intégré à un protocole, l’abstraction disparaît et sa taille réelle devient importanteSi l’on mélange ancien et nouveau code en chargeant des bibliothèques ou en communiquant via un protocole, les décalages deviennent incorrects et les plantages commencent. Au final, la transition impose à tout le monde de séparer les programmes entre « legacy » et « portés, ou au moins vérifiés », ce qui est très pénible
Même remplacer par un type plus grand à la sémantique proche peut casser des choses. Exemple simple : le padding des structures ; et il existe aussi beaucoup de cas où l’on convertit des pointeurs en entiers puis inversement, donc si la représentation interne change, cela ne peut que casser. Que ce soit une bonne pratique ou non est une autre question, mais ce n’est pas rare. Le point clé, c’est la compatibilité ABI
off_t32 bits à une autre construite avec unoff_t64 bits, et le comportement obtenu peut être très imprévisibleDans la structure donnée en exemple, il est dit qu’avec un
time_t32 bits, l’offset decest 8, et qu’avec un type 64 bits il est 12 ; mais en réalité, ne devrait-il pas être 16 ? Commebdoit être aligné sur 64 bits, il devrait y avoir du padding entreaetb. Cela renforce même l’argument de l’auteurQuand on voit tout cela, l’étrange représentation du temps de Windows a quand même un petit avantage : un entier 64 bits comptant des unités de 100 ns depuis le 1er janvier 1601 à 00:00 GMT, dans le calendrier grégorien. La résolution est excellente, et cela fonctionnera encore jusqu’à ce que toute la galaxie soit conquise