Cómo ayuda el análisis de código estático en el espacio GameDev

image1.png


La industria del juego no se detiene y se desarrolla cada día más rápido. Junto con el crecimiento de la industria, la complejidad del desarrollo también crece: hay más código y más errores en él. Por tanto, los proyectos de juegos modernos necesitan una atención especial a la calidad del código. Hoy hablaremos sobre una de las formas de mejorar su código: el análisis estático, y cómo PVS-Studio ayuda en la práctica en el desarrollo de grandes (y no solo) proyectos de juegos.



" Lo más importante que he hecho como programador en los últimos años es perseguir de forma agresiva el análisis de código estático. Incluso más valioso que los cientos de errores graves que he evitado con él es el cambio de mentalidad sobre la forma en que veo la fiabilidad y el código del software calidad. "- John Carmack



Hemos trabajado con los principales desarrolladores de juegos durante muchos años y durante este tiempo hemos logrado hacer muchas cosas interesantes y útiles para la industria de los juegos. Esto no es sorprendente dada la lista de nuestros clientes de la industria del juego. Brindamos soporte activo a nuestros clientes: los ayudamos a integrar PVS-Studio en su propio proceso de desarrollo, corregir los errores encontrados por el analizador e incluso hacer características especiales por encargo.



Además, hacemos mucho desarrollo independiente del analizador en la dirección de GameDev, y también popularizamos PVS-Studio al informar a la gente sobre errores interesantes que encontró en varios videojuegos.



Naturalmente, no sin historias interesantes. Varias de estas historias se discutirán en este artículo.



PVS-Studio y Unity



image2.png


Una de las formas en que promocionamos nuestro producto es escribiendo artículos sobre la revisión de proyectos de código abierto. Todos se benefician de estos artículos: el lector puede ver errores interesantes en un proyecto familiar y aprender algo nuevo por sí mismo, tenemos la oportunidad de mostrar el trabajo de PVS-Studio en código real y los desarrolladores de proyectos pueden aprender sobre los errores y corregirlos por adelantado.



Nuestro primer conocimiento serio de Unity comenzó en 2016, cuando los desarrolladores de este motor de juego lanzaron el código fuente de varios componentes, bibliotecas y demostraciones en su repositorio oficial. Naturalmente, no podíamos pasar por alto un caso tan "sabroso" y queríamos escribir un artículo sobre la verificación del código presentado.



Luego descubrimos que el código de Unity3D (en ese momento el motor se llamaba así) es de muy alta calidad, sin embargo, logramos encontrar bastantes errores graves en él para escribir un artículo .



Dos años después, ocurrió otro evento: esta vez los desarrolladores de Unity lanzaron el código del motor y el editor para el acceso abierto. Y al igual que la vez anterior, no pudimos pasar y verificamos el código fuente del motor. Y por una buena razón: también encontramos un puñado de errores interesantes .



Sin embargo, escribir artículos está lejos de todo. Seguimos trabajando en PVS-Studio, y GameDev es una de las áreas de desarrollo más importantes para nosotros. Por lo tanto, queremos que los desarrolladores de juegos de Unity puedan obtener el mejor análisis posible de sus proyectos.



Uno de los pasos para mejorar la calidad del análisis de los proyectos de Unity fue escribir anotaciones para los métodos definidos en la API de Unity Scripting.



Las anotaciones de métodos son un mecanismo especial utilizado en PVS-Studio. Le permite proporcionar al analizador toda la información necesaria sobre un método en particular. Está escrito en código especial por los propios desarrolladores del analizador (es decir, por nosotros).



Esta información puede ser de un tipo completamente diferente. Por ejemplo: cómo un método puede afectar los parámetros que se le pasan, si puede asignar memoria y si devuelve un valor que debe procesarse. Así, la anotación permite al analizador comprender mejor la lógica de los métodos, lo que le permite detectar errores nuevos y más complejos.



Ya hemos escrito una gran variedad de anotaciones diferentes (por ejemplo, para métodos del espacio de nombres del sistema), y nos complace complementarlas con anotaciones de métodos de la API de scripting de Unity.



Comenzamos a agregar a la lista de anotaciones con una evaluación. ¿Cuantos métodos existen? ¿Cuáles deben anotarse primero? Había muchos métodos en total, y decidimos comenzar anotando los métodos más utilizados.



La búsqueda de métodos populares se llevó a cabo de la siguiente manera: primero, recopilamos un grupo de proyectos de GitHub que usan las capacidades de Unity, y luego, usando una utilidad autoescrita (basada en Roslyn), contamos las llamadas de los métodos que nos interesan. Como resultado, obtuvimos una lista de clases, cuyos métodos se utilizan con mayor frecuencia:



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


A continuación, queda anotar los métodos de estas clases. Creamos un proyecto de prueba y profundizamos en la documentación para obtener la mayor cantidad de información posible sobre estos métodos. Por ejemplo, intentamos pasar null como varios argumentos para ver cómo se comporta el programa.



Durante tales comprobaciones, periódicamente se descubría información interesante no documentada, e incluso encontramos un par de errores interesantes en el motor. Entonces, al ejecutar un código como este:



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


el propio editor de Unity se bloquea directamente (al menos en la versión 2019.3.10f1). Por supuesto, es poco probable que alguien escriba ese código, pero el hecho mismo de que el editor de Unity pueda ser "derribado" ejecutando un script de este tipo es interesante.



Entonces, las anotaciones están escritas. Después de comenzar el análisis, inmediatamente descubrimos nuevos factores desencadenantes. Por ejemplo, el analizador detectó una llamada extraña al método GetComponent :



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

  if (uiManager)
  {
    uiManager.GetComponent<UIManager>();
  }
}


Advertencia del analizador: V3010 Es necesario utilizar el valor de retorno de la función 'GetComponent'. - ADICIONAL EN UIEditorWindow.cs 22



El método GetComponent , incluso por su nombre, implica la devolución de un valor determinado. Es lógico suponer que este mismo valor debería usarse de alguna manera. Ahora (gracias a la nueva anotación) el analizador sabe que una llamada "huérfana" a este método puede indicar un error lógico y le advierte al respecto.



Este está lejos de ser el único desencadenante que apareció en nuestro conjunto de proyectos de prueba después de la adición de nuevas anotaciones; no daré el resto para no hacer que este artículo sea demasiado extenso. Lo principal es que ahora el desarrollo de proyectos de Unity usando PVS-Studio te permite escribir código mucho más seguro y limpio sin errores.



Si desea leer con más detalle sobre nuestro trabajo con anotaciones para los métodos de Unity, puede hacerlo en nuestro artículo: Cómo el analizador PVS-Studio comenzó a encontrar aún más errores en los proyectos de Unity .



Unreal Engine 4



image3.png


Cuando, en 2014, los desarrolladores de Unreal Engine 4 lanzaron el código fuente del motor al público, simplemente no pudimos evitar este proyecto y también escribimos un artículo al respecto . A los desarrolladores del motor les gustó el artículo y solucionaron los errores que encontramos. Pero esto no fue suficiente para nosotros, y decidimos intentar vender la licencia de nuestro analizador a Epic Games.



Epic Games estaba interesado en mejorar su motor usando PVS-Studio, por lo que llegamos a un acuerdo: arreglamos el código de Unreal Engine por nuestra cuenta para que el analizador no emita ninguna advertencia, y los chicos de Epic Games compren nuestra licencia y además recompensarnos por el trabajo que hacemos.



¿Por qué necesita corregir todas las advertencias? El punto es que se puede obtener el máximo beneficio del análisis estático corrigiendo los errores tan pronto como aparecen . Y cuando revisa su proyecto por primera vez, como regla, recibe varios cientos (y a veces miles) de advertencias. Entre todas estas advertencias del analizador, las advertencias emitidas por código recién escrito pueden perderse fácilmente.



A primera vista, este problema se puede resolver con bastante facilidad: solo necesita sentarse y omitir por completo todo el informe, corrigiendo gradualmente los errores. Sin embargo, este método, aunque es más intuitivo, puede llevar tiempo. El método de suprimir archivos es mucho más cómodo y rápido.



Suprimir archivos es una función especial de PVS-Studio, que le permite "ocultar" los activadores del analizador en un archivo especial. Al mismo tiempo, las advertencias ocultas no aparecerán en los registros posteriores: se pueden ver por separado.



Después de haber recibido una gran cantidad de activadores después de la primera verificación, puede agregar todos los activadores detectados al archivo de supresión en un par de clics, y luego, en la siguiente revisión del analizador, recibirá un registro limpio sin un solo activador.



Ahora que las advertencias antiguas ya no se registran, puede detectar fácilmente una nueva advertencia tan pronto como aparezca. Escribimos el código -> lo comprobamos con el analizador -> vimos una nueva advertencia -> solucionamos el error. Así es como saca el máximo partido a su analizador.



Al mismo tiempo, no se olvide de las alarmas que se encuentran en el archivo de supresión: todas, como antes, pueden contener advertencias sobre errores graves y vulnerabilidades. Por lo tanto, vale la pena volver periódicamente a estas advertencias y reducir su número.



Este escenario es conveniente, por supuesto, pero los desarrolladores de Epic Games querían que su código se corrigiera de inmediato y nos lo entregaron.



Y nos pusimos manos a la obra. Después de verificar el código del proyecto, encontramos 1821 un nivel de advertencia Level_1 y Level_2. Analizar tal volumen de advertencias requiere un trabajo serio, y para facilitar todo este proceso, configuramos un análisis de código continuo en nuestro servidor CI.



Se veía así: todas las noches se compilaba la versión actual de Unreal Engine 4 en nuestro servidor, y el análisis se lanzaba automáticamente inmediatamente después de la compilación. Por lo tanto, cuando nuestros muchachos venían a trabajar por la mañana, siempre tenían un informe nuevo del analizador a mano, lo que les permitía realizar un seguimiento del progreso en la corrección de las advertencias. Además, dicho sistema hizo posible verificar la estabilidad de la compilación en cualquier momento ejecutándolo manualmente en el servidor.



Todo el proceso nos llevó 17 días laborables. El programa para corregir las advertencias es el siguiente:



image4.png


De hecho, este cuadro no refleja completamente nuestro trabajo. Después de corregir todas las advertencias, esperamos otros dos días para que aceptaran nuestras últimas solicitudes de extracción. Durante todo este tiempo, continuamos verificando automáticamente la última versión de Unreal Engine, que, a su vez, continuó llenándose con nuevo código. ¿Y, qué piensas? ¡Durante estos dos días, PVS-Studio encontró cuatro errores más en el código! Uno de ellos era especialmente grave y potencialmente podría conducir a un comportamiento indefinido.



Por supuesto, también arreglamos estos errores. Ahora a los desarrolladores de Unreal Engine solo les queda una cosa por hacer: configurar su análisis automático de la misma manera que lo hicimos nosotros. A partir de ese momento, comenzaron a ver advertencias todos los días que se emitían para el código recién escrito. Esto les permitió corregir errores en el código incluso en el momento de su aparición, en las primeras etapas de desarrollo .



Puede leer más sobre cómo trabajamos en el código de Unreal Engine en el blog oficial de Unreal Engine o en nuestro sitio web .



Análisis de varios juegos



image5.png


¿Mencioné que revisamos varios proyectos de código abierto y escribimos artículos sobre ellos? Entonces, ¡tenemos muchos artículos similares sobre proyectos de juegos! ¡Hemos escrito sobre juegos como VVVVVV , Space Engineers , Command & Conquer , osu! e incluso (artículo muy antiguo) Doom 3 . También hemos recopilado los 10 errores más interesantes de la industria de los videojuegos.



También hemos comprobado quizás la mayoría de los motores de código abierto más conocidos. Además de Unity y Unreal Engine 4, proyectos como Godot , Bullet , Amazon Lumberyard , Cry Engine V quedaron bajo nuestra vista.y muchos otros.



La mejor parte de todo esto es que muchos de los errores que describimos fueron posteriormente corregidos por los propios desarrolladores del proyecto. Es bueno sentir que la herramienta que está desarrollando está aportando beneficios reales, visibles y tangibles al mundo.



Puedes ver una lista de todos nuestros artículos, de una forma u otra relacionados con el desarrollo de videojuegos en una página especial de nuestro blog.



Conclusión



Con esto concluye mi breve artículo. ¡Te deseo un código limpio y que funcione correctamente sin errores ni errores!



¿Interesado en el tema del análisis estático? ¿Quieres comprobar si hay errores en tu proyecto? Pruebe PVS-Studio .







Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace de traducción: George Gribkov. Cómo ayuda el análisis de código estático en la industria de GameDev .



All Articles