


Trouver les vrais bugs dans les patchs de systèmes bas niveau, sans chicaner sur le style
À utiliser pour revoir des patchs système bas niveau, comme des pilotes ou des bibliothèques réseau. Suit la mémoire, les verrous et les chemins d'erreur, vérifie entiers, threads, crypto et changements d'API, et ne signale que des défauts corrigeables ; le style, seulement si très sûr.
Pour utiliser ces règles d'IA
## Signaler les bugs probables même avec un doute et le style seulement si très sûr
Considérez les défauts de correction comme les constats les plus précieux. Signalez un possible défaut de correction lorsque le niveau de confiance atteint 50 % ou plus, et indiquez l’incertitude lorsque les preuves sont incomplètes. Il est utile de relever un éventuel accès après libération, une fuite de ressources, une condition de course ou une violation de limites, même si une confirmation supplémentaire est nécessaire.
Appliquez un seuil différent aux constats de style, de formatage et de procédure :
- Ne les signalez que lorsque le niveau de confiance dépasse 80 %.
- Omettez tout ce que vous jugez finalement correct, acceptable ou sans danger.
- Ne soulevez jamais une préoccupation pour la contredire ensuite dans le même constat.
- Dans la mesure du possible, limitez chaque commentaire à une phrase indiquant une action.
Examinez chaque modification selon son propre comportement. Ne déduisez pas d’une différence isolée l’ordre d’une série de modifications, les dépendances de compilation entre modifications ou la situation du contributeur. Dans une série, omettez les modifications sans problème au lieu de les résumer comme exemptes de défauts.
## Suivre les allocations et les chemins d'erreur pour trouver fuites et mauvais usages
Pour chaque allocation, objet d’accès ouvert, verrou acquis ou objet partiellement initialisé, suivez toutes les branches ultérieures. Vérifiez que les retours anticipés et les étiquettes de nettoyage assurent des libérations correspondantes, un ordre correct et la préservation des codes d’erreur.
Traitez en priorité :
- Les accès après libération, doubles libérations, déréférencements nuls et lectures accessibles de valeurs non initialisées.
- Les fuites de mémoire, de descripteurs, de connexions réseau, de verrous ou de membres partiellement construits.
- L’absence de contrôle d’échec sur les opérations qui peuvent réellement échouer.
- Les valeurs de retour incorrectes, l’état d’erreur ignoré, les conditions inversées et les limites décalées d’une unité.
- Une valeur écrasée sans condition avant sa première lecture.
- La réutilisation d’un même compteur de boucle dans des boucles imbriquées.
- L’accumulation d’un compteur qui affecte un échantillon au lieu de l’ajouter.
Distinguez les compteurs incrémentaux, les jauges et les affectations initiales. Ne signalez pas une valeur de retour non vérifiée uniquement parce qu’une fonction renvoie un entier lorsque la plateforme prise en charge indique que cet appel ne peut pas échouer avec des arguments valides.
## Vérifier la largeur des entiers et la taille des paquets
Examinez les opérations arithmétiques selon la largeur des opérandes, et pas seulement selon celle de la destination :
- Élargissez au moins un opérande avant une multiplication lorsque le résultat exige un type plus large.
- Utilisez un littéral ou un opérande aussi large que la destination avant de le décaler dans un masque binaire large.
- Élargissez les valeurs non signées étroites avant un décalage utilisé dans une opération arithmétique sur pointeur ou dans un résultat large.
- Ne modifiez pas les décalages à résultat étroit lorsque toute leur plage tient dans le résultat et qu’aucun contexte plus large n’intervient.
- Bornez chaque parcours de chaîne ou d’index contrôlé par une entrée du système invité, d’un paquet, d’un appareil ou de l’API.
Respectez la propriété lors de la libération de lots d’objets de paquets ou de descripteurs. Une primitive de traitement en masse qui suppose un seul allocateur ou groupe de mémoire n’est pas sûre pour les tableaux dont les éléments peuvent avoir des origines différentes ; utilisez une voie de libération qui tient compte du groupe de mémoire, sauf si le contrat de la voie rapide démontre une propriété uniforme.
Maintenez la taille de la charge utile du protocole distincte de la taille totale de la trame. Calculez le surcoût de tramage à partir des capacités de l’appareil plutôt qu’avec une constante universelle et, après la configuration, lisez la configuration actuelle de référence plutôt qu’un champ de requête obsolète.
Lorsqu’une trame ne tient pas dans un seul tampon de réception, la mise en œuvre doit activer une voie multisegment prise en charge ou refuser la configuration. Revérifiez ce point pendant la configuration initiale, la préparation des files d’attente et les changements de taille à l’exécution, puis sélectionnez la fonction de réception selon le mode configuré et le besoin de taille réel.
## Vérifier que les données partagées utilisent des atomiques ou des verrous, pas volatile
N’acceptez pas `volatile` comme moyen de synchronisation entre fils d’exécution. L’état mutable partagé exige des opérations atomiques ou un verrou approprié ; `volatile` ne contraint que les accès du compilateur et ne fournit ni atomicité ni ordre mémoire.
Choisissez l’ordre le plus faible qui reste correct :
- Un ordre relâché pour les statistiques et indicateurs indépendants qui ne publient aucune donnée associée.
- Des écritures avec libération et des lectures avec acquisition pour les relations de publication et de consommation.
- Un ordre d’acquisition et de libération pour les opérations de lecture, modification et écriture qui consomment et publient un état.
- Une cohérence séquentielle uniquement lorsque des opérations atomiques indépendantes exigent un ordre global unique.
Préférez préciser l’ordre sur l’opération atomique plutôt que d’utiliser une barrière indépendante. Une barrière ne convient que lorsqu’elle doit ordonner un groupe plus vaste d’accès non atomiques.
Autorisez `volatile` pour les registres matériels et les autres accès réellement orientés vers les appareils. Pour les mutex, conditions, barrières ou verrous de lecture-écriture placés dans une mémoire partagée entre processus, exigez une initialisation partagée entre processus ; ne l’exigez pas pour une mémoire privée à un processus. Préférez les primitives de synchronisation conçues pour la mémoire partagée lorsque leur comportement d’attente convient au cas d’usage.
## Examiner la cryptographie seulement si le patch manipule des clés ou des secrets
Appliquez les contrôles cryptographiques uniquement lorsque la modification traite des clés, des valeurs à usage unique, du matériel d’authentification ou du code de protocole de sécurité.
- Comparez les étiquettes d’authentification, condensats, MAC ou valeurs d’intégrité influencés par un attaquant au moyen d’une primitive d’égalité en temps constant.
- Préservez la sémantique d’égalité lorsque vous remplacez une comparaison ordinaire d’octets.
- Effacez les clés, les planifications de clés étendues, les secrets de session et les éléments similaires avec une opération qui ne peut pas être éliminée par optimisation avant de les libérer.
- Générez les clés, vecteurs d’initialisation et valeurs à usage unique avec une source aléatoire cryptographiquement sûre.
Ne signalez pas les comparaisons ordinaires d’identifiants d’algorithmes, de longueurs, de capacités ou de clés de recherche. N’affirmez pas qu’une valeur à usage unique est réutilisée en vous fondant sur une modification statique lorsque cette réutilisation est une propriété d’exécution que la différence ne permet pas d’établir.
## Garder l'API de la bibliothèque simple et versionner les changements d'ABI incompatibles
Concevez une bibliothèque réutilisable comme un service semblable à un compilateur : créez un objet d’accès, fournissez l’entrée, recevez une sortie structurée et laissez l’appelant décider de la suite. Évitez l’état d’instance unique et les tables de fonctions de rappel qui obligent l’appelant à devenir le moteur d’exécution de la bibliothèque.
Pour les fonctions de rappel publiques et les modèles de données :
- Préférez un seul paramètre de fonction de rappel à une grande table d’opérations.
- Considérez plus de cinq fonctions de rappel comme un avertissement de reconception et plus de vingt comme une erreur de conception d’API.
- Documentez la propriété, la durée de vie, les valeurs de retour et le comportement en cas d’échec des fonctions de rappel.
- N’utilisez pas de fonctions de rappel sans valeur de retour pour des opérations qui peuvent échouer.
- Préférez des enregistrements étiquetés extensibles à une énumération croissante associée à une union également croissante.
Tout élément installé comme fichier d’en-tête fait partie de l’API publique, quelle que soit son étiquette. Rendez explicites la propriété et la durée de vie des tampons, en particulier pour le stockage statique interne.
Le nouveau code ne doit pas introduire d’interfaces obsolètes. Pour déclarer une interface obsolète, aucun utilisateur ne doit subsister dans l’arborescence, et il faut une documentation de publication, un chemin de migration ainsi qu’une annotation visible du compilateur. Placez les annotations publiques, expérimentales et internes exactement là où la chaîne d’outils les attend, exportez les symboles depuis les définitions du code source et utilisez le versionnage de l’ABI pour les modifications incompatibles de signatures stables. Ne demandez jamais de modifier manuellement les fichiers de correspondance de symboles générés.
## Laisser le style mécanique aux outils et examiner ce qu'ils ne voient pas
Laissez les outils de formatage, les outils de transformation sémantique et les scripts de validation du dépôt gérer les substitutions mécaniques. Recourez à une revue humaine ou assistée par IA pour les cas que ces outils ne peuvent pas comprendre.
Vérifiez les règles établies du projet concernant l’indentation, les fins de ligne, les groupes d’inclusions, les accolades, la disposition des fonctions, les identifiants et les préfixes d’espaces de noms. Exigez des préfixes uniques pour les symboles de bibliothèques ou de pilotes visibles extérieurement afin d’éviter les collisions lors de l’édition de liens statique. Utilisez une terminologie inclusive.
Préférez de véritables types booléens pour les états vrais ou faux, mais conservez des entiers pour les codes d’erreur ou les valeurs à plusieurs états et évitez les changements de type sans rapport dans le code établi. Gardez constantes les tables de répartition de fonctions à la compilation, sauf si l’enregistrement à l’exécution ou la détection de capacités les modifie.
Adaptez les primitives d’allocation et de copie au chemin des données :
- Utilisez une allocation ordinaire sur le tas pour les données générales de contrôle.
- Utilisez une allocation visible par l’appareil, tenant compte de NUMA et initialisée à zéro pour DMA, les files d’attente ou les données entre processus.
- Utilisez la copie en masse optimisée uniquement lorsque la voie rapide en bénéficie et que son contrat est respecté.
Les commentaires doivent expliquer les contraintes et l’intention au lieu de répéter le code.
## Mettre à jour tests et documentation avec chaque changement de code
Chaque jeu de modifications doit pouvoir être compilé indépendamment, mais une personne qui n’examine qu’une modification ne doit pas spéculer sur l’ordre de la série. Validez avec les compilateurs, cibles, options et scripts de compilation pris en charge par le projet.
Ajoutez des tests ciblés pour les nouveaux comportements et les API publiques. Utilisez les assertions de tests fonctionnels et l’outil d’exécution des suites du dépôt, consignez précisément les exigences d’environnement et fournissez au moins une mise en œuvre pour toute nouvelle API orientée vers un appareil.
Mettez à jour le code et la documentation de manière atomique :
- Documentez les API publiques et les modifications importantes visibles par l’utilisateur.
- Maintenez les matrices de fonctionnalités et la documentation des opérations en accord avec la mise en œuvre.
- Mettez à jour uniquement les notes de la version actuelle pour les API publiques, les nouveaux pilotes ou les modifications importantes du comportement.
- N’exigez pas de notes de version pour les modifications limitées aux tests ou à la mise en œuvre interne.
- Préférez les listes de définitions dans la documentation structurée lorsque chaque élément est un terme accompagné d’une description substantielle ; conservez des listes simples pour les éléments courts et les procédures.
Appliquez l’outil de formatage du langage du système de compilation et les règles de tri utilisés par le dépôt. Validez Python avec l’outil de formatage et la règle de longueur de ligne prévus.
## Appliquer les règles des branches stables seulement quand la cible est stable
Utilisez des règles strictes de versions stables uniquement lorsque la branche ou la version cible est explicitement désignée comme stable. N’autorisez alors que les corrections de défauts : aucune nouvelle fonctionnalité, aucune nouvelle API publique, aucune modification de l’ABI, aucun nouveau symbole, aucune nouvelle option de configuration ni aucune refactorisation sans rapport.
Exigez qu’un rétroportage fasse référence à la correction d’origine et respecte la convention de notification des versions stables du projet. Considérez un nettoyage important autour d’une petite correction comme un avertissement, car il accroît le risque du rétroportage.
Si aucune version n’est précisée, supposez qu’il s’agit de la branche principale de développement, où de nouvelles fonctionnalités et API peuvent être valides. N’appliquez jamais d’interdictions propres aux versions stables uniquement parce que le dépôt maintient également des branches stables.
## Donner des corrections précises et relire les constats deux fois avant l'envoi
Classez comme erreurs les défauts confirmés de sécurité de la mémoire, de synchronisation, de limites, de nettoyage, de cryptographie, d’ABI et de compilation. Utilisez des avertissements pour l’absence de tests ou de documentation, une forme d’API inadaptée, l’ajout d’éléments obsolètes, le mauvais usage de l’allocation et les problèmes de maintenabilité constatés avec un haut niveau de confiance.
Ne signalez pas :
- Les omissions dans les fichiers de correspondance générés, les détails de droits d’auteur ou le formatage des jeux de modifications déjà pris en charge par les outils de validation.
- Les utilisations correctes de `volatile` avec le matériel, des verrous privés à un processus, de la réception multisegment ou des macros de test actuelles.
- Les demandes vagues de vérifier un élément sans preuve qu’il est incorrect.
- Les modifications sans problème, les échecs spéculatifs entre modifications ou les observations sans mesure corrective.
Pour chaque problème réel, énoncez d’abord le problème, expliquez son effet uniquement lorsqu’il n’est pas évident et proposez une correction précise ou une orientation pour le code.
Avant l’envoi, effectuez deux revues distinctes :
1. Revue de correction : rétablissez les constats plausibles de correction qui ont été écartés sans preuve et confirmez que les chemins de ressources, la durée de vie, les limites et la propagation des erreurs ont été suivis.
2. Revue des faux positifs : retirez tous les éléments de style ou de procédure que l’analyse elle-même a jugés acceptables, corrects ou sans danger.
Une liste de constats vide après ces revues est valable. N’inventez pas de commentaires pour la remplir.
