Como a análise de código estático ajuda na indústria GameDev

( 4 de dezembro de 2020)

A indústria de jogos está em constante evolução e se desenvolve mais rápido do que uma bala em alta velocidade. Junto com o crescimento da indústria, a complexidade do desenvolvimento também aumenta: a base de código está ficando maior e o número de bugs também está crescendo. Portanto, os projetos de jogos modernos precisam prestar atenção especial à qualidade do código. Hoje iremos cobrir uma das maneiras de tornar seu código mais decente, que é a análise estática, bem como como o PVS-Studio na prática ajuda no desenvolvimento de projetos de jogos de vários tamanhos.

“A coisa mais importante que fiz como programador nos últimos anos foi para buscar agressivamente a análise de código estático. Ainda mais valioso do que as centenas de bugs graves que evitei com ele é a mudança de mentalidade sobre a maneira como vejo a confiabilidade do software e a qualidade do código. ”- John Carmack

Trabalhamos com os principais desenvolvedores de jogos há muitos anos e, durante esse tempo, conseguimos fazer muitas coisas interessantes e úteis para a indústria de jogos. Não é uma surpresa, dada a lista de nossos clientes da indústria de jogos. Apoiamos ativamente nossos clientes: para integrar PVS-Studio em seu próprio processo de desenvolvimento, corrigir erros encontrados pelo analisador e até mesmo fazer recursos personalizados especiais.

Além disso, fazemos muitos desenvolvimentos independentes de o analisador na direção do GameDev, além de promover o PVS-Studio, contando às pessoas sobre erros interessantes que ele encontrou em vários videogames.

Claro, temos algumas histórias interessantes para contar. Este artigo cobrirá vários desses casos.

PVS-Studio e Unity

Uma das maneiras de promover nosso produto é escrevendo artigos sobre a verificação de projetos abertos. Todos se beneficiam com esses artigos: o leitor tem a chance de verificar alguns erros incomuns em um projeto familiar e aprender algo novo. Quanto à equipe PVS-Studio, temos a oportunidade de mostrar o trabalho feito em código real, para que os desenvolvedores de projetos possam aprender sobre os erros e corrigi-los com antecedência.

Nosso primeiro contato importante com o Unity aconteceu em 2016, quando os desenvolvedores deste motor de jogo abriram o código-fonte de vários componentes, bibliotecas e demos em seu repositório oficial. Não é à toa que não poderíamos ignorar um caso tão atraente e queríamos escrever um artigo sobre como verificar o código postado.

Então descobrimos que o código Unity3D (naquela época, o mecanismo era chamado assim) era de alta qualidade. Mesmo assim, conseguimos encontrar muitos erros graves nele. Havia o suficiente deles para escrever um artigo .

Dois anos depois, outra coisa aconteceu – os desenvolvedores do Unity abriram o código do motor e o próprio editor. E assim como da vez anterior, não pudemos deixar de notar e verificamos o código-fonte do motor. E não foi à toa – também encontramos um grupo de falhas cativantes.

Ao mesmo tempo, nossas intenções vão muito além de apenas escrever artigos. Continuamos trabalhando no PVS-Studio, e GameDev é uma das áreas mais significativas para o nosso desenvolvimento. Portanto, queremos que os desenvolvedores de jogos do Unity consigam obter a melhor análise possível de seus projetos.

Uma das etapas para melhorar a qualidade da análise de projetos do Unity foi escrever anotações para métodos definidos na API de script do Unity .

A anotação de método é um mecanismo especial usado no PVS-Studio. Ele permite que um usuário forneça ao analisador todas as informações necessárias sobre um método específico. Ele é escrito em um código especial pelos próprios desenvolvedores do analisador (ou seja, por nós).

Essas informações podem ser de vários tipos. Por exemplo: como o método pode afetar os parâmetros passados ​​a ele, se ele pode alocar memória e se ele retorna um valor que deve ser manipulado. Assim, a anotação permite ao analisador compreender melhor a lógica dos métodos, permitindo-lhe detectar erros novos e mais complexos.

Já escrevemos um grande número de anotações diferentes (por exemplo, para métodos do Sistema namespace) e ficamos felizes em adicionar anotações de método da API de script do Unity a eles.

Começamos a estender a lista de anotações com uma avaliação. Quantos métodos existem no total? Quais devem ser anotados primeiro? Havia muitos métodos no total, então decidimos começar anotando os mais usados.

É assim que procurávamos métodos populares: primeiro, reunimos um conjunto de projetos do GitHub que usam recursos do Unity e, em seguida, usamos um utilitário autoescrito (baseado em Roslyn) para calcular chamadas para os métodos em que estávamos interessados. Como resultado, obtivemos uma lista de classes cujos métodos eram usados ​​com mais frequência:

  • UnityEngine.Vector3
  • UnityEngine.Mathf
  • UnityEngine.Debug
  • UnityEngine.GameObject
  • UnityEngine.Material
  • UnityEditor.EditorGUILayout
  • UnityEngine.Component
  • UnityEngine.Object
  • UnityEngine.GUILayout
  • UnityEngine.Quaternion

Em seguida, permaneceu para anotar os métodos dessas classes. Criamos um projeto de teste e vasculhamos a documentação para obter o máximo possível de informações sobre esses métodos. Por exemplo, tentamos passar null como vários argumentos para ver como o programa se comportaria.

Durante essas verificações, de tempos em tempos, estávamos descobrindo algumas informações não documentadas interessantes. Até encontramos alguns bugs notáveis ​​no motor. Por exemplo, quando estamos executando o seguinte código:

MeshRenderer renderer = cube.GetComponent();
Material m = renderer.material;
List<int> outNames = null;
m.GetTexturePropertyNameIDs(outNames);

o editor do Unity trava (pelo menos na versão 2019.3.10f1). Claro, é improvável que alguém escreva esse código. Ainda assim, o fato de que o editor do Unity pode travar ao executar esse tipo de script é curioso.

Então, escrevemos as anotações. Depois de executar a análise, encontramos imediatamente novos acionamentos. Por exemplo, o analisador detectou uma chamada estranha para o método GetComponent :

void OnEnable()
{
GameObject uiManager = GameObject.Find("UIRoot"); if (uiManager)
{
uiManager.GetComponent();
}
}

Aviso do analisador: V3010 O valor de retorno da função GetComponent deve ser utilizado. – ADICIONAL NO CURRENT UIEditorWindow.cs 22

O método GetComponent implica o retorno de um valor específico mesmo devido ao seu nome. É lógico supor que esse valor deva ser usado de alguma forma. Agora, graças à nova anotação, o analisador sabe que uma chamada “autônoma” para este método pode indicar um erro lógico e avisa sobre isso.

Este não é o único aviso que apareceu no conjunto de nosso teste os projetos após adicionar novas anotações. Não vou citar o resto, para não tornar este artigo muito extenso. O principal é que agora o desenvolvimento de projetos Unity usando PVS-Studio permite que você escreva um código muito mais seguro e limpo sem bugs.

Se você gostaria de ler mais sobre nosso trabalho com anotações para métodos Unity, aqui está o artigo: Como o analisador PVS-Studio começou a encontrar ainda mais erros em projetos Unity .

Unreal Engine 4

Quando, em 2014, os desenvolvedores do Unreal O mecanismo 4 abriu o código-fonte do mecanismo, simplesmente não conseguimos superar esse projeto e também escrevemos um artigo sobre ele. Os desenvolvedores do motor gostaram do artigo e corrigiram os erros que encontramos. Mas isso não foi suficiente para nós, e decidimos tentar vender a licença do nosso analisador para a Epic Games.

A Epic Games estava interessada em melhorar seu mecanismo com PVS-Studio, então concordamos com o seguinte : corrigimos o código do Unreal Engine por conta própria para que o analisador não emita nenhum aviso, e os caras da Epic Games compram nossa licença e adicionalmente nos recompensam pelo trabalho realizado.

Por que todos os avisos tiveram que ser fixo? O fato é que se pode obter o máximo benefício da análise estática corrigindo os erros exatamente quando eles aparecem . Quando você verifica seu projeto pela primeira vez, geralmente recebe várias centenas (e às vezes milhares) de avisos. Entre todos esses acionamentos do analisador, é fácil perder avisos emitidos para código recém-escrito.

À primeira vista, esse problema pode ser resolvido com bastante facilidade: você só precisa sentar e examinar todo o relatório , corrigindo erros gradualmente. No entanto, embora esse método seja mais intuitivo, pode levar algum tempo. É muito mais conveniente e rápido usar arquivos suprimidos.

Arquivos suprimidos são um recurso especial do PVS-Studio que permite ocultar avisos do analisador em um arquivo especial. No entanto, os avisos ocultos não aparecerão nos logs subsequentes: você pode visualizá-los separadamente.

Depois de ter muitos acionamentos após a primeira verificação, você pode adicionar todos os avisos detectados ao arquivo suprimido em alguns cliques e você obterá um log limpo sem uma única entrada após a próxima verificação.

Agora que os avisos antigos não estão mais incluídos no log, você pode detectar facilmente um novo aviso imediatamente quando ele aparecer. Esta é a ordem das ações: escrever o código -> verificar com o analisador -> localizar um novo aviso -> corrigir o erro. É assim que você obterá o máximo do uso do analisador.

Ao mesmo tempo, não se esqueça dos avisos no arquivo de supressão: eles ainda podem conter avisos sobre erros importantes e vulnerabilidades, como antes. Portanto, deve-se retornar a esses avisos e reduzir seu número regularmente.

Sem dúvida, esse cenário é conveniente, mas os desenvolvedores da Epic Games queriam que seu código fosse corrigido imediatamente, então eles passaram o tarefa para nós.

E começamos a trabalhar. Depois de verificar o código do projeto, encontramos 1821 avisos de Nível_1 e Nível_2. Analisar um volume tão grande de avisos exige um trabalho sério e, para facilitar todo esse processo, configuramos uma análise de código contínua em nosso servidor de CI.

Parecia assim: todas as noites em nosso servidor, o atual versão do Unreal Engine 4 foi construída, e imediatamente após a construção, a análise foi iniciada automaticamente. Assim, quando nossos caras vinham trabalhar pela manhã, eles sempre tinham um novo relatório do analisador, o que os ajudava a acompanhar o andamento da eliminação de avisos. Além disso, este sistema nos permitiu verificar a estabilidade da compilação a qualquer momento, executando-o manualmente no servidor.

Todo o processo levou 17 dias úteis. O cronograma para correção de erros era o seguinte:

Na verdade, este cronograma não reflete totalmente o nosso trabalho. Depois de corrigir todos os avisos, esperamos mais dois dias para que eles aceitassem nossas últimas solicitações de pull. Todo esse tempo, a última versão do Unreal Engine estava sendo verificada automaticamente, que, por sua vez, continuava sendo atualizada com o novo código. Então, o que você acha que aconteceu? Durante aqueles dois dias, o PVS-Studio encontrou mais quatro erros no código! Um deles foi crucial e poderia levar a um comportamento indefinido.

Claro, também corrigimos esses erros. Naquele ponto, os desenvolvedores do Unreal Engine só tinham uma coisa: configurar a análise automática em seu próprio lugar, assim como fizemos. A partir daquele momento, eles começaram a ver todos os dias avisos emitidos para o código que haviam acabado de escrever. Isso permitiu que eles corrigissem os erros no código logo que apareciam – nos primeiros estágios de desenvolvimento .

Você pode ler mais sobre como trabalhamos no código do Unreal Engine no blog oficial do Unreal Engine ou em nosso site .

Análise de vários jogos

Eu mencionei que nós verificar vários projetos abertos e escrever artigos sobre eles? Portanto, agora temos muitos artigos semelhantes sobre projetos de jogos! Escrevemos sobre jogos como VVVVVV , Space Engineers , Comando & Conque r, osu! e até mesmo (um artigo muito antigo) Doom 3 . Também compilamos os 10 principais dos bugs de software mais interessantes da indústria de videogame.

Então, verificamos provavelmente a maioria dos mecanismos de código aberto bem conhecidos. Além do Unity e do Unreal Engine 4, projetos como Godot , Bullet , Amazon Lumberyard , Cry Engine V e muitos outros estão sob nossa mira.

A melhor parte de tudo isso é que muitos dos bugs que descrevemos foram posteriormente corrigidos pelos próprios desenvolvedores do projeto. É bom sentir que a ferramenta que você está desenvolvendo traz benefícios reais, visíveis e tangíveis para o mundo.

Você pode ver uma lista de todos os nossos artigos relacionados ao desenvolvimento de videogames de uma forma ou de outra em um página especial do nosso blog.

Conclusão

Nesse ponto, meu artigo chega ao fim. Desejo a você um código limpo e funcionando corretamente, sem bugs e erros!

Interessado no tópico de análise estática? Quer verificar se há erros em seu projeto? Experimente o PVS-Studio .

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *