The story of how PVS-Studio found an error in the library used in ... PVS-Studio

Picture 1

This is a short story about how using PVS-Studio it was possible to find an error in the source code of the library used in PVS-Studio. Moreover, not theoretical, but actual - the error was manifested in practice when using the library in the analyzer.

In PVS-Studio_Cmd (as well as some other utilities) we use a special library for parsing command line arguments - CommandLine.

Today, I was engaged in supporting the new mode in PVS-Studio_Cmd, and it just so happened that I had to use this library for parsing arguments. In the process of writing code, I am also debugging it, since I have to work with unfamiliar APIs.

So, the code is written, compiled, run for execution, ii ...

Picture 3

Code execution goes inside the library, where an exception of type NullReferenceException occurs . From the side it’s not very clear - I don’t pass any explicit null references to the method.

Just in case, I look at the comments on the called method. It is very unlikely that they describe the conditions for an exception of type NullReferenceException (since usually, as it seems to me, exceptions of this type are unforeseen).

Picture 2

In the comments to the method, there is no information about any NullReferenceException (which, however, is expected).

To see what exactly causes the exception (and where), I decided to download the source code of the project, collect and connect the debug version of the library to the analyzer. The source code for the project is available on GitHub . Version 1.9.71 is required, since it is precisely this type that is now used in the analyzer.

I load the appropriate version of the source code, collect, connect the debug library to the analyzer, run the code for execution and see:

Picture 4

So, the place of the exception is clear - helpInfo is null , which causes an exception of type NullReferenceException when accessing the Left instance property.

And then I became thoughtful. Recently, PVS-Studio for C # has been not badly improved in various areas, including in the field of search for dereferencing of potentially null references. In particular, the interprocedural analysis was improved. Therefore, it immediately became interesting for me to check the source code to see if PVS-Studio could find the error under discussion.

I checked the source code, and among other warnings, I saw exactly what I was hoping for.

PVS-Studio Warning : V3080 Possible null dereference inside method at 'helpInfo.Left'. Consider inspecting the 2nd argument: helpInfo. Parser.cs 405

Yes, there it is! Exactly what you need. Let's look at the source code in a bit more detail.

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

The analyzer generates a warning message when calling the DisplayHelpVerbText method and warns about the second argument - helpInfo . Note that this method is in the then branch of the if statement . The conditional expression is composed in such a way that then- branch can be executed with the following values ​​of variables:

Let's see the body of the DisplayHelpVerbText method:

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

Since verb == null (see the method call) we are interested in the then- branch of the if statement . Although the situation with the else branch will be similar, we will consider the then- branch, since in our particular case execution was through it. Remember that helpInfo can be null .

Now let's look at the body of the HelpVerbOptionAttribute.InvokeMethod method. Actually, you already saw it in the screenshot above:

 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 is called unconditionally, although helpInfo can be null . The analyzer warned about this, and this happened.


It turned out funny that with the help of PVS-Studio it was possible to find an error in the code of the library that is used in PVS-Studio. I think this is a kind of continuation of the answer to the question “Does PVS-Studio find errors in PVS-Studio code?”. :) It can find errors not only in the PVS-Studio code, but also in the code of the libraries used.

Finally, I propose to download the analyzer and try to check your project - what if you can find something interesting there too?

If you want to share this article with an English-speaking audience, then please use the link to the translation: Sergey Vasiliev. The story of how PVS-Studio found an error in the library used in ... PVS-Studio


All Articles