有关PVS-Studio如何在... PVS-Studio中使用的库中发现错误的故事

图片1

这是一个简短的故事,说明如何使用PVS-Studio可以在PVS-Studio中使用的库的源代码中发现错误。 此外,不是理论上的,而是实际的-在分析仪中使用该库时,该错误在实践中得到了体现。

在PVS-Studio_Cmd(以及其他一些实用程序)中,我们使用特殊的库来解析命令行参数-CommandLine。

今天,我参与了在PVS-Studio_Cmd中支持新模式的工作,碰巧我不得不使用这个解析参数库。 在编写代码的过程中,我也正在调试它,因为我必须使用不熟悉的API。

因此,代码被编写,编译,运行以执行,ii ...

图片3


代码执行传递到发生NullReferenceException类型的异常的库中。 从侧面看,这不是很清楚-我没有将任何显式的null引用传递给该方法。

以防万一,我看一下被调用方法的注释。 它们不太可能描述NullReferenceException类型的异常的条件(因为在我看来通常是无法预料的,​​因为这种类型的异常是不可预见的)。

图片2


在对该方法的注释中,没有有关任何NullReferenceException的信息(但是,这是预期的)。

为了查看导致异常的确切原因(在何处),我决定下载项目源代码,编译该库的调试版本并将其连接到分析器。 该项目的源代码可在GitHub上找到 。 需要使用1.9.71版,因为正是分析仪现在使用的是这种类型。

我加载了适当版本的源代码,进行收集,将调试库连接到分析器,运行代码以进行执行,然后查看:

图片4


因此,异常的位置很明显-helpInfonull ,这在访问Left实例属性时会导致类型为NullReferenceException的异常。

然后我变得体贴。 最近,用于C#的PVS-Studio在各个领域都得到了很好的改进,包括在搜索潜在的空引用的反引用方面。 特别是,改进了过程间分析。 因此,检查源代码以查看PVS-Studio是否可以找到正在讨论的错误对我来说立即变得很有趣。

我检查了源代码,在其他警告中,我确切地看到了我所希望的。

PVS-Studio警告V3080在'helpInfo.Left'的方法中可能会取消引用。 考虑检查第二个参数:helpInfo。 解析器405

是的,那里! 正是您所需要的。 让我们更详细地看一下源代码。

private bool DoParseArgumentsVerbs( string[] args, object options, ref object verbInstance) { var verbs = ReflectionHelper.RetrievePropertyList<VerbOptionAttribute>(options); var helpInfo = ReflectionHelper.RetrieveMethod<HelpVerbOptionAttribute>(options); if (args.Length == 0) { if (helpInfo != null || _settings.HelpWriter != null) { DisplayHelpVerbText(options, helpInfo, null); // <= } return false; } .... } 

当调用DisplayHelpVerbText方法时,分析器会生成警告消息,并警告第二个参数-helpInfo 。 请注意,此方法位于if语句then分支中。 条件表达式的构成方式使得可以使用以下变量值执行then-分支:

  • helpInfo == null ;
  • _settings.HelpWriter!= null ;

让我们看一下DisplayHelpVerbText方法的主体:

 private void DisplayHelpVerbText( object options, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb) { string helpText; if (verb == null) { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, null, out helpText); } else { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, verb, out helpText); } if (_settings.HelpWriter != null) { _settings.HelpWriter.Write(helpText); } } 

由于动词== null (请参见方法调用),因此我们对if语句then-分支感兴趣。 尽管else分支的情况将类似,但我们将考虑then分支,因为在我们的特殊情况下执行是通过它进行的。 请记住, helpInfo可以为null

现在,让我们看一下HelpVerbOptionAttribute.InvokeMethod方法的主体。 实际上,您已经在上面的屏幕截图中看到了它:

 internal static void InvokeMethod( object target, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb, out string text) { text = null; var method = helpInfo.Left; if (!CheckMethodSignature(method)) { throw new MemberAccessException( SR.MemberAccessException_BadSignatureForHelpVerbOptionAttribute .FormatInvariant(method.Name)); } text = (string)method.Invoke(target, new object[] { verb }); } 

即使helpInfo可以为null ,也将无条件调用helpInfo.Left 。 分析仪对此进行了警告,并发生了这种情况。

结论

有趣的是,借助PVS-Studio,有可能在PVS-Studio中使用的库代码中发现错误。 我认为这是对“ PVS-Studio是否在PVS-Studio代码中发现错误?”问题的答案的一种延续。 :)它不仅可以在PVS-Studio代码中发现错误,而且可以在所用库的代码中发现错误。

最后,我建议下载分析器并尝试检查您的项目-如果在那里也可以找到有趣的东西怎么办?



如果您想与讲英语的读者分享这篇文章,请使用以下链接:Sergey Vasiliev。 有关PVS-Studio如何在... PVS-Studio中使用的库中发现错误的故事

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


All Articles