Esta é uma pequena história sobre como usar o PVS-Studio foi possível encontrar um erro no código fonte da biblioteca usada no PVS-Studio. Além disso, não teórico, mas real - o erro foi manifestado na prática ao usar a biblioteca no analisador.
No PVS-Studio_Cmd (assim como em alguns outros utilitários), usamos uma biblioteca especial para analisar argumentos de linha de comando - CommandLine.
Hoje eu estava envolvido no suporte ao novo modo no PVS-Studio_Cmd, e aconteceu que eu tive que usar essa biblioteca de argumentos de análise. No processo de escrever código, também estou depurando, pois tenho que trabalhar com APIs desconhecidas.
Então, o código é escrito, compilado, executado para execução, ii ...
A execução do código passa para a biblioteca onde
ocorre uma exceção do tipo
NullReferenceException . Por um lado, não está muito claro - não passo nenhuma referência nula explícita ao método.
Apenas no caso, eu olho para os comentários sobre o método chamado. É muito improvável que eles descrevam as condições para uma exceção do tipo
NullReferenceException (já que geralmente, como me parece, exceções desse tipo são imprevisíveis).
Nos comentários do método, não há informações sobre nenhuma
NullReferenceException (que, no entanto, é esperada).
Para ver o que exatamente causa a exceção (e onde), decidi baixar o código-fonte do projeto, compilar e conectar a versão de depuração da biblioteca ao analisador. O código fonte do projeto
está disponível no GitHub . A versão 1.9.71 é necessária, pois é precisamente esse tipo que agora é usado no analisador.
Carrego a versão apropriada do código-fonte, coleciono, conecto a biblioteca de depuração ao analisador, executo o código para execução e consulte:
Portanto, o local da exceção é claro -
helpInfo é
nulo , o que causa uma exceção do tipo
NullReferenceException ao acessar a propriedade da instância
Left .
E então fiquei pensativo. Recentemente, o PVS-Studio for C # foi bem aprimorado em várias áreas, inclusive no campo de pesquisa para desreferenciamento de referências potencialmente nulas. Em particular, a análise interprocedural foi aprimorada. Portanto, tornou-se imediatamente interessante verificar o código-fonte para ver se o PVS-Studio poderia encontrar o erro em discussão.
Eu verifiquei o código fonte e, entre outros avisos, vi exatamente o que estava esperando.
PVS-Studio Warning :
V3080 Possível desreferência nula dentro do método em 'helpInfo.Left'. Considere inspecionar o segundo argumento: helpInfo. Parser.cs 405
Sim está aí! Exatamente o que você precisa. Vamos dar uma olhada no código fonte com mais detalhes.
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);
O analisador gera uma mensagem de aviso ao chamar o método
DisplayHelpVerbText e avisa sobre o segundo argumento -
helpInfo . Observe que esse método está na ramificação
then da
instrução if . A expressão condicional é composta de tal maneira que o ramo pode ser executado com os seguintes valores de variáveis:
- helpInfo == null ;
- _settings.HelpWriter! = null ;
Vamos ver o corpo do método
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); } }
Como o
verbo == null (veja a chamada do método), estamos interessados no ramo
então da
instrução if . Embora a situação com o ramo
else seja semelhante, consideraremos o ramo
então , uma vez que em nosso caso particular a execução foi superada. Lembre-se de que
helpInfo pode ser
nulo .
Agora, vamos examinar o corpo do método
HelpVerbOptionAttribute.InvokeMethod . Na verdade, você já viu na captura de tela acima:
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 é chamado incondicionalmente, mesmo que
helpInfo possa ser
nulo . O analisador alertou sobre isso, e isso aconteceu.
ConclusãoFicou engraçado que, com a ajuda do PVS-Studio, foi possível encontrar um erro no código da biblioteca usada no PVS-Studio. Penso que este é um tipo de continuação da resposta à pergunta “O PVS-Studio encontra erros no código do PVS-Studio?”. :) Pode encontrar erros não apenas no código do PVS-Studio, mas também no código das bibliotecas utilizadas.
Por fim, proponho
fazer o download do analisador e tentar verificar seu projeto - e se você também encontrar algo interessante lá?

Se você deseja compartilhar este artigo com um público que fala inglês, use o link para a tradução: Sergey Vasiliev.
A história de como o PVS-Studio encontrou um erro na biblioteca usada em ... PVS-Studio