大家好! 新年快到了,所以现在是盘点即将到来的一年的时候了。 按照传统,我们很高兴介绍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,
来自文章“
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";
来自文章“
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;
文章“
通过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_DEFAULT和
LANG_USER_DEFAULT的声明来修复错误。 程序执行结果:1024。
第一名“先尝试,然后信任”
排名第一绝非易事。 这里一定有一些非凡而迷人的东西。 最初,对于本文,我选择了20多个有趣的错误,但其中没有什么值得一提的。 那时我回想起了我的同事谢尔盖·瓦西里耶夫(Sergey Vasiliev)的文章。 该文章仅阐述了一个错误。 该错误的妙处在于它直接影响了我们分析仪的工作。 怎么了 您已经可以从文章标题中获得它:“
关于PVS-Studio如何在... PVS-Studio中使用的库中发现错误的故事 ”。 在这里,我感到懒惰,无法给出错误的描述,因此建议您按照链接查找详细信息。 :)我保证这是值得的。 而且,文章简短。
结论
我希望这些错误对您来说是未解决的,并且本文不会使您感到厌倦。 仅作记录,您始终可以
下载 PVS-Studio分析仪以查找您和第三方项目中的错误,以取悦您自己,同事和任何Tom,Dick或Harry。 让错误减少,让自我完善的时间更多! :)
你读到最后吗? 我祝贺达到新的水平! 不要错过我们博客中的upcomimg文章-2019年发现的
Java和
C ++项目中的最佳bug。