Linux supprime l’API `strncpy` après 6 ans et plus de 360 correctifs
(phoronix.com/news)- Dans Linux 7.2, les usages internes au noyau de l’API
strncpyont disparu, ce qui entraîne la suppression définitive de cette interface de copie de chaînes dont l’abandon était prévu depuis longtemps strncpy()copie un nombre d’octets donné, mais son comportement de terminaison NUL n’est pas intuitif, ce qui en a fait pendant des années une source de bugs dans le noyau- Sa tendance à remplir inutilement le tampon de destination avec des zéros provoquait aussi des problèmes de performances, et il a fallu environ 6 ans et 362 commits pour l’éliminer
- Lors du merge de vendredi, non seulement l’API elle-même a été retirée, mais aussi la dernière implémentation spécifique à l’architecture per-CPU
- Le code du noyau doit désormais choisir des fonctions de remplacement selon l’usage, comme
strscpy(),strscpy_pad(),strtomem_pad(),memcpy_and_pad()oumemcpy()
strncpy disparaît de Linux 7.2
- Linux 7.2 supprime définitivement du noyau l’API
strncpy, dont l’abandon était prévu de longue date - Après 6 années de nettoyage, il ne reste plus aucun code interne au noyau utilisant l’interface
strncpy - Ce changement ne se limite pas à un simple remplacement de fonction : il s’apparente à l’élimination, à l’échelle du noyau, d’anciennes pratiques de copie de chaînes
Ampleur du travail nécessaire à sa suppression
- La suppression de
strncpya nécessité environ 362 commits - Le travail a progressé en éliminant étape par étape les usages de
strncpydans le noyau - Avec Linux 7.2, ce chantier de nettoyage arrive à son terme
Pourquoi strncpy posait problème dans le noyau
strncpyétait considérée depuis des années dans le noyau Linux comme une source récurrente de bugs- Deux comportements en particulier étaient problématiques
- La sémantique et le comportement de terminaison NUL n’étaient pas intuitifs, ce qui favorisait les erreurs d’utilisation
- Le remplissage redondant du tampon de destination avec des zéros entraînait un coût de performances inutile
Le merge qui a acté sa suppression
- Le merge effectué vendredi a supprimé l’API
strncpy - La même opération a aussi retiré la dernière implémentation
strncpyspécifique à l’architecture per-CPU
API de remplacement à utiliser dans le code du noyau
- À la place de
strncpy, il faut choisir une fonction adaptée à la cible de copie et aux conditions de terminaisonstrscpy(): à utiliser pour une destination terminée par NULstrscpy_pad(): à utiliser lorsqu’une destination terminée par NUL nécessite un remplissage par zérosstrtomem_pad(): à utiliser pour des champs de largeur fixe non terminés par NULmemcpy_and_pad(): à utiliser pour une copie bornée avec padding explicitememcpy(): à utiliser pour une copie mémoire dont la longueur est connue
1 commentaires
Commentaires sur Hacker News
Autrefois, on se moquait des développeurs du noyau Linux, pourtant parmi les meilleurs développeurs C du monde, en disant qu’ils n’étaient même pas capables de créer des types
stringbufferoustringview, mais il faut reconnaître qu’à l’époque il n’existait pas encore de véritable consensus sur le sujetLa personne qui avait déjà vu la bonne direction, c’était Dennis Ritchie, qui avait proposé en 1990 un type de pointeur gras pour C. Si cela avait été intégré à C99, cela aurait été un ajout parfait ; si le comité l’avait adopté, le monde aurait peut-être été assez différent
En 2007, il y a eu une deuxième occasion avec l’article de Walter Bright, “C's greatest mistake”, qui expliquait plus clairement l’idée de slice/stringview, essentiellement la même que celle de Ritchie, mais cela n’a pas non plus été intégré à C11. On en est à C23 et ce n’est toujours pas là ; à la place, on a eu
_Genericet les VLA, alors autant faire la fêteEn cherchant, je suis aussi tombé sur un post Reddit sur le même sujet, et la polémique de « l’abri à vélos » m’a fait rire : https://www.reddit.com/r/C_Programming/comments/90uq7c/cs_bi...
Je me demande pourquoi le comportement de décadence des tableaux C en pointeurs a été conçu ainsi. J’ai vu l’explication selon laquelle le but était de pouvoir compiler du code B en C avec un minimum de changements ; en B, une déclaration de tableau définissait en fait un pointeur et un tableau, puis initialisait ce pointeur pour qu’il pointe vers le premier élément du tableau
Le plus gros problème aujourd’hui, c’est que la bibliothèque standard du C reste bloquée à l’époque K&R, et que même des fonctionnalités du langage ajoutées en C99, comme les structures en argument ou en valeur de retour, n’ont pas été reflétées dans les API de la bibliothèque standard. Rien qu’avec des structures de plage sous forme de paire pointeur/taille dans la bibliothèque standard, et de nouvelles fonctions de chaîne ou des fonctions de chaîne modernisées qui les utilisent, la situation pourrait déjà nettement s’améliorer
On dit que strncpy dans le noyau Linux a été pendant des années une « source tenace de bugs », à cause de sa sémantique contre-intuitive, de la gestion de la terminaison NUL et du coût en performances dû au remplissage inutile de zéros dans la destination
Chaque fois qu’on m’a demandé une revue de code C, j’ai cherché les
strncpy, et j’y ai toujours trouvé des bugsCertaines choses m’irritent depuis 40 ans. Les chaînes terminées par NUL, et maintenant même les chaînes non UTF-8 en entrée/sortie
C’est aussi le cas des conventions de fin de ligne en LF, CR ou CRLF, et des champs séparés par des pipes ou des virgules. Si on avait utilisé des caractères ASCII non ambigus comme GS, FS et RS, l’encodage/décodage des fins de ligne serait devenu un simple problème d’E/S, et HT/VT/CR/LF/FF auraient pu rester, au sens propre, dans le code lié à l’affichage
Toute la saleté liée à la gestion des échappements dans les données séparées par des virgules disparaît, ce qui simplifie énormément les choses
La norme Unicode dit qu’il faut traiter CR, LF, CRLF et ces caractères, mais aussi la tabulation verticale et le saut de page, comme des séparateurs de ligne
Les fins de ligne comme LF, CR ou CRLF relèvent aussi des conventions des systèmes d’exploitation, et il vaut mieux qu’un langage de programmation n’essaie pas de « deviner » la bonne fin de ligne. Cela crée plus de problèmes que cela n’en résout, et encore une fois, c’est surtout un problème propre à Windows ; c’est à Microsoft de faire entrer Windows dans le siècle actuel
La dernière fois que j’ai dû manipuler un fichier CSV en bash, je l’ai converti en interne en RS et FS pour le traiter
Au lieu de
strncpy, le code du noyau Linux recommande d’utiliserstrscpy()pour les destinations terminées par NUL,strscpy_pad()pour les destinations terminées par NUL qui nécessitent un remplissage en zéros,strtomem_pad()pour les champs de largeur fixe non terminés par NUL,memcpy_and_pad()pour les copies bornées avec padding explicite, etmemcpy()pour les copies mémoire dont la longueur est connueÇa ressemble à un cauchemar, et je ne vois pas pourquoi cela devrait être aussi complexe
Je trouve préférable que, lors de la lecture du code, l’intention du développeur soit claire rien qu’à travers le choix de la fonction
strncpya toujours été compliqué de toute façonC’est précisément dans ce genre de travail répétitif et ingrat que se fait le vrai travail de l’ingénierie système
Ce type de grand projet d’infrastructure, qui rend le noyau Linux plus fiable tout en le maintenant exploitable en production tout au long du processus, ne se joue pas sur quelques mois mais sur des dizaines d’années
En revanche, je ne sais pas si l’on peut produire des avancées importantes et durables à ce rythme. Ce n’est pas vraiment une plainte, plutôt une forme de paradoxe de l’infrastructure critique
C’est un travail à la fois impressionnant et qui force à l’humilité. C’est étonnant de voir qu’autant de personnes y ont contribué
Les « nouvelles fonctionnalités géniales » obtiennent facilement de la reconnaissance, mais sur quelque chose d’aussi fondamental que le noyau, retirer de mauvaises fonctionnalités est peut-être encore plus important
Quand, dans 50 ans, on vivra à une époque où les gens auront oublié comment lire le code source, où les résidus de Claude/Codex s’accumuleront en silence en brûlant l’essentiel de l’énergie de la planète, ce genre de travail restera sans doute comme une légende de « l’âge fondateur »
C’est aussi la seule personne qui sache ce qu’est l’Unix epoch
Je pense que les chaînes terminées par 0 sont la plus grosse erreur de l’histoire de l’informatique. Les chaînes à la Pascal étaient bien plus sûres
Cela reste un pointeur vers un tableau de caractères terminé par 0, mais avec un champ de longueur juste avant le premier octet pointé. En supposant l’absence de caractères NUL intégrés, c’est aussi compatible avec les chaînes C, et les fonctions de type BSTR peuvent exploiter la valeur de longueur
Pendant un temps, même 16 bits ont peut-être paru excessifs, et aujourd’hui 32 bits peuvent sembler trop petits. C, qu’on présente comme un langage à « typage fort », est en réalité assez permissif là où c’était important
Je n’ai pas écrit de code lié à Pascal depuis plus de 30 ans, mais je garde le vague souvenir d’avoir déjà trouvé son système de chaînes trop pénible à utiliser à l’époque
Il y a énormément de souffrance et de bricolage juste parce qu’il manque un type chaîne de caractères
strncpyutilise aussi ce type et ces fonctions, non ?Je me demande ce qui rendait la réécriture des usages de
strncpysi difficile au point que cela ait pris 6 ansJ’aimerais savoir si son usage était si répandu, si c’était un chantier de long terme mené seulement quand on modifiait déjà le même fichier, ou s’il y avait d’autres difficultés
J’ai déjà dû gérer du code dans une appli Win32 qui utilisait des chaînes remplies d’espaces. La chaîne de destination était remplie avec des espaces, mais le dernier octet restait quand même un caractère nul
Il fallait utiliser des versions dédiées des fonctions de chaîne pour les opérations de longueur, de copie, etc. Je ne sais pas pourquoi c’était fait comme ça, mais vu l’âge du codebase, ça venait peut-être du comportement des structures Pascal
chardans une base SQL. Contrairement àvarchar, les champscharsont complétés avec des espaces