Top 10 des bugs dans les projets C # pour 2019

Image 1

Salutations à tous les amoureux des insectes. La nouvelle année arrive bientôt, il est donc temps de faire le point sur l'année qui s'en va. Par tradition, un classement des erreurs les plus intéressantes découvertes par l'équipe PVS-Studio dans les projets ouverts C # pour 2019. Êtes-vous prêt? Commençons alors.

Dixième place: «confondre tout le monde»


V3066 Ordre incorrect possible des arguments passés à la méthode 'AdjustCellBorderStyle': 'isFirstDisplayedRow' et 'isFirstDisplayedColumn'. DataGridViewComboBoxCell.cs 1934

protected override void OnMouseMove(DataGridViewCellMouseEventArgs e) { .... dgvabsEffective = AdjustCellBorderStyle( DataGridView.AdvancedCellBorderStyle, dgvabsPlaceholder, singleVerticalBorderAdded, singleHorizontalBorderAdded, isFirstDisplayedRow, // <= isFirstDisplayedColumn); // <= .... } 

Erreur de l'article " WinForms: Erreurs, Holmes ". L'analyseur indique que lors du passage d'arguments à la méthode, les deux derniers arguments ont été inversés. Jetez un œil à la déclaration AdjustCellBorderStyle :

 public virtual DataGridViewAdvancedBorderStyle AdjustCellBorderStyle( DataGridViewAdvancedBorderStyledataGridViewAdvancedBorderStyleInput, DataGridViewAdvancedBorderStyle dataGridViewAdvancedBorderStylePlaceholder, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded, bool isFirstDisplayedColumn, bool isFirstDisplayedRow) { .... } 

Il semble que l'analyseur ait raison. Souvent, certains arguments sont délibérément passés dans l'ordre inverse, par exemple, afin d'échanger certaines variables. Mais il ne semble pas que ce soit exactement le cas. Tout d'abord, les variables de type booléen sont confuses. Deuxièmement, les noms des méthodes sont également courants: pas de «Swap» ou «Reverse». De plus, il n'est pas si difficile de se tromper comme ceci: les gens perçoivent souvent différemment l'ordre de la paire ligne / colonne.

Neuvième place: "L'Infini est proche"


V3110 Récursion infinie possible dans la méthode 'TryValidateModel'. PrefixedModuleUpdater.cs 48

 public bool TryValidateModel(object model, string prefix) { return TryValidateModel(model, Prefix(prefix)); } 

Erreur de l'article " Recherche et analyse des erreurs dans le code Orchard CMS ". Une erreur a été commise qui provoque une récursion infinie. Pour comprendre comment cette erreur a pu être commise, vous devez examiner la surcharge de la méthode TryValidateModel :

 public bool TryValidateModel(object model) { return _updateModel.TryValidateModel(model); } 

Il est probable que dans le premier cas un appel du formulaire soit utilisé:

 public bool TryValidateModel(object model, string prefix) { return _updateModel.TryValidateModel(model, Prefix(prefix)); } 

Le code compilé car _updateModel est de type IUpdateModel et la classe actuelle implémente également l'interface IUpdateModel .

Huitième place: «Essayez, trouvez»


V3091 Analyse empirique. Il est possible qu'une faute de frappe soit présente à l'intérieur du littéral de chaîne: "ID du groupe de gestion". Le mot «Id» est suspect. Constants.cs 36

 public class HelpMessages { public const string SubscriptionId = "Subscription Id of the subscription associated with the management"; public const string GroupId = "Management Group Id"; // <= public const string Recurse = "Recursively list the children of the management group"; public const string ParentId = "Parent Id of the management group"; public const string GroupName = "Management Group Id"; // <= public const string DisplayName = "Display Name of the management group"; public const string Expand = "Expand the output to list the children of the management group"; public const string Force = "Force the action and skip confirmations"; public const string InputObject = "Input Object from the Get call"; public const string ParentObject = "Parent Object"; } 

L'erreur provient de l'article « Azure PowerShell:« fondamentalement inoffensif ». L'analyseur soupçonne que la constante GroupName a été initialisée avec une chaîne d'erreur. Il devrait probablement y avoir quelque chose comme « Management Group Name » . Il est difficile de juger de la criticité de cette erreur, mais elle est particulièrement rare et difficile à détecter.

Septième place: "Juste négligé"


V3078 L'ordre de tri d'origine sera perdu après un appel répétitif à la méthode 'OrderBy'. Utilisez la méthode 'ThenBy' pour conserver le tri d'origine. GridModel.Selection.cs 107

 internal partial class GridModel { private void BuildCellSelectionRegions(....) { .... this.MergeCellSelectionRegions(selectedItemsInView .OrderBy(c => c.Column.ItemInfo.LayoutInfo.Line) .OrderBy(c => c.RowItemInfo.LayoutInfo.Line)); } } 

Erreur de l'article " Vérification de l'interface utilisateur de Telerik pour UWP pour se familiariser avec PVS-Studio ". En raison de la réutilisation de OrderBy pour une collection déjà triée, le résultat du tri précédent sera perdu. Vous devez utiliser ThenBy :

 this.MergeCellSelectionRegions(selectedItemsInView .OrderBy(c => c.Column.ItemInfo.LayoutInfo.Line) .ThenBy(c => c.RowItemInfo.LayoutInfo.Line)); 

De telles erreurs sont commises par négligence ou par ignorance. Je pense que le copier-coller est à blâmer.

Sixième place: «Le code est documenté», ont-ils déclaré


V3009 Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. MaskedTextProvider.cs 1529

 public bool Remove(out int testPosition, out MaskedTextResultHint resultHint) { .... if (lastAssignedPos == INVALID_INDEX) { .... return true; // nothing to remove. } .... return true; } 

Erreur de l'article " Vérification du code source des bibliothèques .NET Core avec l'analyseur statique PVS-Studio ". La méthode retournera toujours true . Oui, c'est une erreur, mais quelque chose d'autre est curieux. Un commentaire détaillé est joint à la méthode:

Supprime le dernier caractère de la chaîne formatée. (Supprimer le dernier caractère de la chaîne virtuelle). A la sortie, le paramètre out contient la position où l'opération a été réellement effectuée. Cette position est relative à la chaîne de test. Le paramètre MaskedTextResultHint out donne plus d'informations sur le résultat de l'opération. Renvoie vrai en cas de succès, faux sinon.

Concentrez-vous sur la dernière phrase. Mais qui a jamais lu ces commentaires? Mais sérieusement, une telle erreur se glisse facilement, par exemple, lors de la refactorisation ou du débogage. Nous voulions vérifier l'option lorsque le résultat de la méthode sera toujours vrai , eh bien, nous avons oublié de tout renvoyer tel qu'il était.

Cinquième place: "Indexez-moi, immédiatement!"


V3102 Accès suspect à l'élément de l'objet 'seq' par un index constant à l'intérieur d'une boucle. XmlQueryRuntime.cs 738

 public bool MatchesXmlType(IList<XPathItem> seq, ....) { .... for (int i = 0; i < seq.Count; i++) { if (!CreateXmlType(seq[0]).IsSubtypeOf(....)) return false; } return true; } 

Erreur de l'article " Vérification du code source des bibliothèques .NET Core avec l'analyseur statique PVS-Studio ". Lors de la traversée de la collection seq , la boucle for utilise par erreur uniquement l'accès à son premier élément à toutes les itérations (index 0 au lieu de i ).

Quatrième place: «Juste un dollar et pas assez»


V3138 Le littéral de chaîne contient une expression interpolée potentielle. Envisagez d'inspecter: e. SSPIHandleCache.cs 42

 internal static void CacheCredential(SafeFreeCredentials newHandle) { try { .... } catch (Exception e) { if (!ExceptionCheck.IsFatal(e)) { NetEventSource.Fail(null, "Attempted to throw: {e}"); } } } 

Erreur de l'article " Vérification du code source des bibliothèques .NET Core avec l'analyseur statique PVS-Studio ". La chaîne «Tentative to throw: {e}» semble être interpolée. En raison du caractère $ manquant, la représentation sous forme de chaîne de l'exception e ne sera pas remplacée dans la chaîne. Par conséquent, la chaîne sera utilisée «telle quelle».

Troisième place: "Il n'y a pas d'issue"


V3008 [CWE-563] La variable 'this.linker.s3.region' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 116, 114. AWSSDK.DynamoDBv2.Net45 S3Link.cs 116

 public string Region { get { .... } set { if (String.IsNullOrEmpty(value)) { this.linker.s3.region = "us-east-1"; } this.linker.s3.region = value; } } 

Erreur de l'article « Recherche d'erreurs dans le code source du SDK Amazon Web Services pour .NET ». Dans le corps du bloc if , le retour a été ignoré. Par conséquent, la variable this.linker.s3.region obtiendra toujours une valeur , y compris une chaîne vide et null .

Deuxième place: "Devenez en ordre!"


V3070 La variable non initialisée 'LANG_USER_DEFAULT' est utilisée lors de l'initialisation de la variable 'LOCALE_USER_DEFAULT'. NativeMethods.cs 890

 internal static class NativeMethods { .... public static readonly int LOCALE_USER_DEFAULT = MAKELCID(LANG_USER_DEFAULT); public static readonly int LANG_USER_DEFAULT = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); .... } 

Erreur de l'article " WinForms: Erreurs, Holmes ". L'ordre d'initialisation des champs de classe est mélangé. Pour calculer la valeur du champ LOCALE_USER_DEFAULT , utilisez le champ LANG_USER_DEFAULT , qui n'est pas encore initialisé et a une valeur de 0. La variable LANG_USER_DEFAULT n'est utilisée nulle part ailleurs dans le code. Pour comprendre à quoi cette erreur conduit, un programme de test a été écrit contenant des méthodes du code WinForms. Par souci de simplicité, certaines constantes réelles ont été remplacées par leurs valeurs réelles:

 internal static class NativeMethods { public static readonly int LOCALE_USER_DEFAULT = MAKELCID(LANG_USER_DEFAULT); public static readonly int LANG_USER_DEFAULT = MAKELANGID(0x00, 0x01); public static int MAKELANGID(int primary, int sub) { return ((((ushort)(sub)) << 10) | (ushort)(primary)); } public static int MAKELCID(int lgid) { return MAKELCID(lgid, 0x0); } public static int MAKELCID(int lgid, int sort) { return ((0xFFFF & lgid) | (((0x000f) & sort) << 16)); } } class Program { static void Main() { System.Console.WriteLine(NativeMethods.LOCALE_USER_DEFAULT); } } 

À la suite du lancement, les éléments suivants seront affichés sur la console: 0. Nous allons maintenant corriger l'erreur en échangeant la déclaration des champs LOCALE_USER_DEFAULT et LANG_USER_DEFAULT . Le résultat du programme sous cette forme: 1024.

Première place: "Faites confiance, mais vérifiez"


La première place est toujours difficile. Il doit y avoir quelque chose d'extraordinaire et de très intéressant. Au départ, j'ai sélectionné plus de vingt erreurs intéressantes pour cet article, mais il n'y avait rien de digne de leur première place. Et puis je me suis souvenu d'un article de mon collègue Sergey Vasiliev, consacré à une seule erreur. La beauté de cette erreur est qu'elle a directement affecté le fonctionnement de notre analyseur. Comment? Cela ressort déjà du titre de l'article " Historique de la façon dont PVS-Studio a trouvé une erreur dans la bibliothèque utilisée dans ... PVS-Studio ". Encore une fois, la paresse n'a pas été annulée. :) Et là, j'ai complètement honte et je ne donnerai pas de description de l'erreur, mais je proposerai de suivre le lien vers l'article et d'en savoir plus. Je le garantis - ça vaut le coup. Et l'article est court.

Conclusion


J'espère que les erreurs ont été intéressantes, mais l'article ne s'est pas fatigué. Je vous rappelle que vous pouvez toujours télécharger l' analyseur PVS-Studio pour rechercher vous-même les erreurs dans vos propres projets et ceux de tiers, pour vous faire plaisir, amis et collègues. Et qu'il y ait moins d'erreurs et plus de temps pour s'améliorer! :)

As-tu lu? Félicitations pour le passage au niveau suivant! Dans les articles suivants de notre blog, les meilleurs bugs de 2019 dans les projets Java et C ++ sont mis en évidence .

Image 2




Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Sergey Khrenov. Top 10 des bugs trouvés dans les projets C # en 2019 .

Source: https://habr.com/ru/post/fr481178/


All Articles