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

图片1

这是关于PVS-Studio如何帮助我们在PVS-Studio中使用的库的源代码中发现错误的简短故事。 这不是理论上的错误,而是实际的错误-在分析仪中使用该库时,实际上会出现该错误。

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

今天,我在PVS-Studio_Cmd中支持新模式,碰巧我不得不使用该库来解析命令行参数。 在编写代码时,我还调试了它,因为我必须使用不熟悉的API。

因此,代码被编写,编译,执行并...

图片3

代码执行在发生NullReferenceException类型的异常的库中进行。 从侧面看还不太清楚-我没有将任何null引用传递给该方法。

可以肯定的是,我查看对被调用方方法的注释。 它们几乎不可能描述NullReferenceException类型的异常的发生条件(在我看来,通常不提供这种类型的异常)。

图片2

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

为了查看导致异常的确切原因(及其发生的位置),我决定下载该项目的源代码,进行构建,然后将对库的调试版本的引用添加到分析器。 该项目的源代码可从GitHub获得 。 我们需要该库的1.9.71版本。 现在是分析仪中使用的一种。

我下载了相应版本的源代码,构建了库,将对调试库的引用添加到了分析器,执行了代码并看到:

图片4

因此,发生异常的地方很清楚-helpInfo具有null值,当访问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.Left是无条件调用的,而helpInfo可以为null 。 分析仪对此进行了警告,事实就是这样。

结论

很高兴我们借助PVS-Studio设法在PVS-Studio中使用的库的源代码中发现错误。 我认为这是对“ PVS-Studio是否在PVS-Studio源代码中发现错误?”问题的一种答案。 :)分析仪不仅可以在PVS-Studio代码中发现错误,而且可以在所用库的代码中发现错误。

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

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


All Articles