
A indústria de jogos não pára e está se desenvolvendo cada vez mais rápido a cada dia. Junto com o crescimento da indústria, a complexidade do desenvolvimento também cresce: há mais código e mais bugs nele. Portanto, os projetos de jogos modernos precisam de atenção especial à qualidade do código. Hoje vamos falar sobre uma das maneiras de tornar seu código melhor - a análise estática, bem como como o PVS-Studio ajuda na prática no desenvolvimento de grandes (e não apenas) projetos de jogos.
" A coisa mais importante que fiz como programador nos últimos anos foi buscar agressivamente a análise estática de código. Ainda mais valioso do que as centenas de bugs graves que evitei com ela é a mudança de mentalidade sobre a maneira como vejo a confiabilidade do software e o código qualidade. "- John Carmack
Trabalhamos com os principais desenvolvedores de jogos por muitos anos e, durante esse tempo, conseguimos fazer muitas coisas interessantes e úteis para a indústria de jogos. Isso não é surpreendente, dada a lista de nossos clientes da indústria de jogos. Oferecemos suporte ativo aos nossos clientes: os ajudamos a integrar o PVS-Studio em seu próprio processo de desenvolvimento, corrigir erros encontrados pelo analisador e até mesmo fazer recursos especiais sob encomenda.
Além disso, fazemos muito desenvolvimento independente do analisador na direção do GameDev, e também popularizamos o PVS-Studio, contando às pessoas sobre bugs interessantes encontrados em vários videogames.
Naturalmente, não sem histórias interessantes. Várias dessas histórias serão discutidas neste artigo.
PVS-Studio e Unity

Uma das maneiras pelas quais estamos promovendo nosso produto é escrevendo artigos sobre a revisão de projetos de código aberto. Todos se beneficiam com esses artigos: o leitor pode observar erros interessantes em um projeto familiar e aprender algo novo por si mesmo, temos a oportunidade de mostrar o trabalho do PVS-Studio em código real e os desenvolvedores de projeto podem aprender sobre os erros e corrigi-los antecipadamente.
Nosso primeiro contato sério com o Unity começou em 2016, quando os desenvolvedores deste motor de jogo lançaram o código-fonte de vários componentes, bibliotecas e demos em seu repositório oficial. Naturalmente, não poderíamos ignorar um caso tão "saboroso" e queríamos escrever um artigo sobre como verificar o código apresentado.
Então descobrimos que o código Unity3D (naquela época o motor era chamado assim) é de muito alta qualidade, entretanto, conseguimos encontrar muitos erros sérios nele para escrever um artigo .
Dois anos depois, outro evento aconteceu - desta vez os desenvolvedores do Unity liberaram o código da própria engine e o editor para acesso aberto. E assim como da vez anterior, não pudemos passar por aqui e checar o código-fonte do motor. E por um bom motivo: também encontramos um punhado de erros interessantes .
No entanto, escrever artigos está longe de tudo. Continuamos trabalhando no PVS-Studio, e GameDev é uma das áreas de desenvolvimento mais importantes para nós. Portanto, queremos que os desenvolvedores de jogos do Unity possam obter a melhor análise possível de seus projetos.
Uma das etapas para melhorar a qualidade da análise de projetos do Unity para nós foi escrever anotações para os métodos definidos na API de script do Unity.
As anotações de método são um mecanismo especial usado no PVS-Studio. Ele permite que você 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 um tipo completamente diferente. Por exemplo: como um 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 processado. 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 uma grande variedade de anotações diferentes (por exemplo, para métodos do namespace System) e ficamos felizes em complementá-las com anotações de método da API de script do Unity.
Começamos a adicionar à lista de anotações com uma avaliação. Quantos métodos existem? Quais devem ser anotados primeiro? Havia muitos métodos no total, e decidimos começar anotando os métodos usados com mais frequência.
A busca por métodos populares foi realizada da seguinte forma: primeiro, coletamos um conjunto de projetos do GitHub que usam os recursos do Unity e, em seguida, usando um utilitário autoescrito (baseado em Roslyn), contamos as chamadas dos métodos nos quais estamos interessados. Como resultado, obtivemos uma lista de classes, cujos métodos são 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, resta anotar os métodos dessas classes. Criamos um projeto de teste e nos aprofundamos na documentação para obter o máximo de informações possível sobre esses métodos. Por exemplo, tentamos passar null como vários argumentos para ver como o programa se comporta.
Durante essas verificações, informações não documentadas interessantes eram descobertas periodicamente - e até encontramos alguns bugs interessantes no mecanismo. Então, ao executar um código como este:
MeshRenderer renderer = cube.GetComponent<MeshRenderer>();
Material m = renderer.material;
List<int> outNames = null;
m.GetTexturePropertyNameIDs(outNames);
o próprio editor do Unity trava diretamente (pelo menos na versão 2019.3.10f1). É improvável, claro, que alguém escreva esse código, mas o próprio fato de que o editor do Unity pode ser "derrubado" ao executar tal script é interessante.
Então, as anotações são escritas. Depois de iniciar a análise, descobrimos imediatamente novos gatilhos. Por exemplo, o analisador detectou uma chamada estranha para o método GetComponent :
void OnEnable()
{
GameObject uiManager = GameObject.Find("UIRoot");
if (uiManager)
{
uiManager.GetComponent<UIManager>();
}
}
Aviso do analisador: V3010 O valor de retorno da função 'GetComponent' deve ser utilizado. - ADICIONAL NA CURRENT UIEditorWindow.cs 22
O método GetComponent , mesmo pelo seu nome, implica o retorno de um determinado valor. É lógico supor que esse mesmo valor deva ser usado de alguma forma. Agora (graças à nova anotação) o analisador sabe que uma chamada "órfã" para esse método pode indicar um erro lógico e avisa sobre isso.
Este está longe de ser o único gatilho que apareceu em nosso conjunto de projetos de teste após a adição de novas anotações - não vou citar o resto para não tornar este artigo muito grande. 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ê quiser ler mais detalhadamente sobre nosso trabalho com anotações para métodos Unity, você pode fazê-lo em nosso 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 Engine 4 lançaram o código-fonte do motor ao público, simplesmente não podíamos ignorar esse projeto e também escrevemos um artigo sobre ele . Os desenvolvedores do motor gostaram do artigo e corrigiram os bugs que encontramos. Mas isso não foi o 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 motor usando PVS-Studio, então concordamos em um acordo: corrigimos o código do Unreal Engine por conta própria para que o analisador não emita nenhum aviso por ele, e os caras da Epic Games compram nossa licença e adicionalmente nos recompense pelo trabalho que fazemos.
Por que você precisou corrigir todos os avisos? O ponto é que o benefício máximo da análise estática pode ser obtido corrigindo os erros assim que eles aparecem . E quando você verifica seu projeto pela primeira vez, como regra, você recebe várias centenas (e às vezes milhares) de avisos. Entre todos esses avisos do analisador, os avisos emitidos para códigos recém-escritos podem se perder facilmente.
À primeira vista, este problema pode ser resolvido com bastante facilidade: basta sentar e ignorar completamente o relatório inteiro, corrigindo os erros gradualmente. No entanto, esse método, embora mais intuitivo, pode levar tempo. O método de supressão de arquivos é muito mais conveniente e rápido.
Suprimir arquivos são uma função especial do PVS-Studio, que permite "ocultar" os gatilhos do analisador em um arquivo especial. Nesse caso, os avisos ocultos não aparecerão nos logs subsequentes: eles podem ser vistos separadamente.
Tendo recebido um grande número de gatilhos após a primeira verificação, você pode adicionar todos os gatilhos detectados ao arquivo suprimido com alguns cliques e, então, na próxima verificação do analisador, você receberá um log limpo sem um único gatilho.
Agora que os avisos antigos não são mais registrados, você pode localizar facilmente um novo aviso assim que ele aparecer. Escrevemos o código -> verificamos com o analisador -> vimos um novo aviso -> corrigimos o erro. É assim que você obtém o máximo do seu analisador.
Ao mesmo tempo, não se esqueça dos alarmes que estão no arquivo de supressão: todos eles, como antes, podem conter avisos sobre erros graves e vulnerabilidades. Portanto, vale a pena retornar periodicamente a esses avisos e reduzir seu número.
Esse cenário é conveniente, é claro, mas os desenvolvedores da Epic Games queriam que seu código fosse corrigido imediatamente e o entregaram para nós.
E temos que trabalhar. Depois de verificar o código do projeto, encontramos 1821 um nível de aviso Level_1 e Level_2. Analisar esse volume de avisos requer 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, a versão atual do Unreal Engine 4 era compilada em nosso servidor e a análise era automaticamente iniciada imediatamente após a construção. Portanto, quando nossos funcionários vinham trabalhar pela manhã, eles sempre tinham um novo relatório do analisador em mãos, permitindo-lhes acompanhar o progresso na correção dos avisos. Além disso, esse sistema tornou possível verificar a estabilidade da construção a qualquer momento, executando-a manualmente no servidor.
Todo o processo demorou 17 dias úteis. O cronograma para correção de avisos é o seguinte:

Na verdade, este gráfico não reflete totalmente nosso trabalho. Depois de corrigir todos os avisos, esperamos mais dois dias para que aceitassem nossas últimas solicitações de pull. Todo esse tempo, a verificação automática da última versão do Unreal Engine continuou a funcionar para nós, que, por sua vez, continuou a ser reabastecida com novo código. E o que você acha? Durante esses dois dias, o PVS-Studio encontrou mais quatro erros no código! Um deles era especialmente sério e poderia levar a um comportamento indefinido.
Claro, também corrigimos esses erros. Agora, os desenvolvedores do Unreal Engine só têm uma coisa: para configurar sua análise automática da mesma maneira que fizemos. A partir desse momento, eles começaram a ver todos os dias avisos emitidos para o código recém-escrito. Isso permitiu que eles corrigissem bugs no código mesmo no momento de seu aparecimento - nos estágios iniciais 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 verificamos vários projetos de código aberto e escrevemos artigos sobre eles? Então, temos muitos artigos semelhantes sobre projetos de jogos! Escrevemos sobre jogos como VVVVVV , Space Engineers , Command & Conquer , osu! e até mesmo (artigo muito antigo) Doom 3 . Também compilamos os 10 principais bugs mais interessantes da indústria de videogames.
Também verificamos talvez a maioria dos mecanismos de código aberto mais conhecidos. Além de Unity e Unreal Engine 4, projetos como Godot , Bullet , Amazon Lumberyard , Cry Engine V vieram à nossa vistae muitos outros.
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 está trazendo benefícios reais, visíveis e tangíveis para o mundo.
Você pode ver uma lista de todos os nossos artigos, de uma forma ou de outra relacionados ao desenvolvimento de videogames em uma página especial do nosso blog.
Conclusão
Isso conclui meu breve artigo. 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 .


Se você quiser compartilhar este artigo com um público que fala inglês, use o link de tradução: George Gribkov. Como a análise de código estático ajuda na indústria de GameDev .