2019年C#项目中发现的十大bug

图片1

大家好! 新年快到了,所以现在是盘点即将到来的一年的时候了。 按照传统,我们很高兴介绍PVS-Studio团队在2019年开放C#项目中发现的错误的最主要列表。准备好了吗? 然后开始吧。

第十名“愚弄大家”


V3066传递给“ AdjustCellBorderStyle”方法的参数的可能错误顺序:“ isFirstDisplayedRow”和“ isFirstDisplayedColumn”。 DataGridViewComboBoxCell.cs 1934

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

来自文章“ WinForms:错误,Holmes ”的错误 。 分析器指出,当该方法的最后两个参数混合在一起时。 让我们看一下AdjustCellBorderStyle声明:

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

看起来分析仪是正确的。 开发人员经常有意地以相反的顺序传递一些参数,例如,在变量之间交换。 但事实并非如此。 首先,将布尔类型变量混合在一起。 其次,没有异常方法的名称:没有“交换”或“反向”。 此外,犯这样的错误并不难:人们对“行/列”排序顺序的理解不同。

第九名“如此接近永恒”


V3110'TryValidateModel '方法内可能进行的无限递归。 PrefixedModuleUpdater.cs 48

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

文章“ 扫描Orchard CMS的错误代码”中的错误 。 有一个错误导致无限递归。 为了掌握错误的产生方式,必须考虑TryValidateModel方法的重载:

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

第一种情况很可能也应该使用这样的调用:

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

代码已成功编译,因为_updateModel具有IUpdateModel类型,并且当前类还实现​​了IUpdateModel接口。

第八名“如果可以找到我”


V3091实证分析。 字符串文字中可能存在拼写错误:“管理组ID”。 “ Id”一词可疑。 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"; } 

来自文章“ Azure PowerShell:几乎无害 ”的错误。 分析器怀疑GroupName常量由不正确的字符串初始化。 可能应该有类似“管理组名称”的名称 。 此错误的严重性仍然值得怀疑,但是该错误绝对罕见并且很难检测。

第七名“只是被忽视”


V3078重复调用'OrderBy'方法后,原始排序顺序将丢失。 使用“ ThenBy”方法保留原始排序。 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)); } } 

文章“ 检查Telerik UI for UWP作为PVS-Studio入门的一种方法 ”中的错误。 由于对已排序集合的OrderBy的重复调用,先前排序的结果将丢失。 在这种情况下,必须使用ThenBy

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

此类错误是由于疏忽大意或无知造成的。 我认为复制粘贴应归咎于此。

他们说,“代码已记录在案”第六名


V3009这种方法总是返回一个相同的'true'值,这很奇怪。 MaskedTextProvider.cs 1529

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

文章“ 通过PVS-Studio静态分析器检查.NET Core库源代码 ”中的错误。 该方法将始终返回true 。 是的,这是一个错误,但是还有另一件事真的很奇怪。 该方法后面是详细注释:

从格式化的字符串中删除最后一个字符。 (删除虚拟字符串中的最后一个字符)。 退出时,out参数包含实际执行操作的位置。 此位置相对于测试字符串。 MaskedTextResultHint输出参数可提供有关操作结果的更多信息。 成功 返回 true 否则 返回 false

注意最后一句话。 谁还会读这些评论? 但是,如果我们认真对待它,就很容易造成这种错误,例如在重构或调试过程中。 好吧,作者希望在方法的结果始终为true时检查变体但忘记将所有内容都返回原样。

第五名:“现在索引我!”


V3102通过循环内的常量索引可疑访问“ seq”对象的元素。 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; } 

文章“ 通过PVS-Studio静态分析器检查.NET Core库源代码 ”中的错误。 在for循环中遍历seq集合时,开发人员错误地在所有迭代中仅使用对其第一个元素的访问(索引为0而不是i )。

第四名“仅缺一美元”


V3138字符串文字包含潜在的内插表达式。 考虑检查: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}"); } } } 

文章“ 通过PVS-Studio静态分析器检查.NET Core库源代码 ”中的错误。 显然,应该插入字符串“尝试抛出:{e}” 。 由于缺少$字符,因此e异常的行表示形式将不会放入字符串中。 结果,该行将“按原样”使用。

第三名“没有出路”


V3008 [CWE-563]连续两次为“ this.linker.s3.region”变量分配值。 也许这是一个错误。 检查行: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; } } 

文章“ 在.NET的Amazon Web Services SDK源代码中搜索错误中的错误if块的正文中未包含返回值 。 结果, this.linker.s3.region变量将始终获得值,包括空行和null。

第二名“正装!”


V3070在初始化“ LOCALE_USER_DEFAULT”变量时使用未初始化的变量“ LANG_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); .... } 

来自文章“ WinForms:错误,Holmes ”的错误 。 类字段的初始化顺序很混乱。 要计算LOCALE_USER_DEFAULT字段的值,使用LANG_USER_DEFAULT字段,该字段目前尚未初始化,为0。在代码中的任何其他位置均未使用该变量。 为了得到该错误的原因,编写了一个完整的测试程序,其中包含WinForms代码中的方法。 为了简化起见,它们的实际值代替了某些常量,它们被替换为:

 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); } } 

执行结果如下:0.现在,通过交换字段LOCALE_USER_DEFAULTLANG_USER_DEFAULT的声明来修复错误。 程序执行结果:1024。

第一名“先尝试,然后信任”


排名第一绝非易事。 这里一定有一些非凡而迷人的东西。 最初,对于本文,我选择了20多个有趣的错误,但其中没有什么值得一提的。 那时我回想起了我的同事谢尔盖·瓦西里耶夫(Sergey Vasiliev)的文章。 该文章仅阐述了一个错误。 该错误的妙处在于它直接影响了我们分析仪的工作。 怎么了 您已经可以从文章标题中获得它:“ 关于PVS-Studio如何在... PVS-Studio中使用的库中发现错误的故事 ”。 在这里,我感到懒惰,无法给出错误的描述,因此建议您按照链接查找详细信息。 :)我保证这是值得的。 而且,文章简短。

结论


我希望这些错误对您来说是未解决的,并且本文不会使您感到厌倦。 仅作记录,您始终可以下载 PVS-Studio分析仪以查找您和第三方项目中的错误,以取悦您自己,同事和任何Tom,Dick或Harry。 让错误减少,让自我完善的时间更多! :)

你读到最后吗? 我祝贺达到新的水平! 不要错过我们博客中的upcomimg文章-2019年发现的JavaC ++项目中的最佳bug。

图片2

Source: https://habr.com/ru/post/zh-CN481174/


All Articles