En informática , el análisis de programas [1] es el proceso de analizar automáticamente el comportamiento de los programas informáticos en relación con una propiedad como la corrección, la robustez, la seguridad y la vitalidad. El análisis de programas se centra en dos áreas principales: la optimización del programa y la corrección del programa . La primera se centra en mejorar el rendimiento del programa al tiempo que se reduce el uso de recursos, mientras que la segunda se centra en garantizar que el programa haga lo que se supone que debe hacer.
El análisis del programa se puede realizar sin ejecutar el programa ( análisis de programa estático ), durante el tiempo de ejecución ( análisis de programa dinámico ) o en una combinación de ambos.
En el contexto de la corrección del programa, el análisis estático puede descubrir vulnerabilidades durante la fase de desarrollo del programa. [2] Estas vulnerabilidades son más fáciles de corregir que las encontradas durante la fase de prueba, ya que el análisis estático conduce a la raíz de la vulnerabilidad.
Debido a que muchas formas de análisis estático son computacionalmente indecidibles , los mecanismos para realizarlo pueden no siempre finalizar con la respuesta correcta. Esto puede dar como resultado falsos negativos ("no se encontraron problemas" cuando el código de hecho tiene problemas) o falsos positivos , o porque es posible que nunca devuelvan una respuesta incorrecta pero también es posible que nunca finalicen. A pesar de estas limitaciones, el análisis estático aún puede ser valioso: el primer tipo de mecanismo puede reducir la cantidad de vulnerabilidades, mientras que el segundo a veces puede brindar una garantía sólida de la ausencia de ciertas clases de vulnerabilidades.
Las optimizaciones incorrectas son altamente indeseables. Por lo tanto, en el contexto de la optimización de programas, existen dos estrategias principales para manejar análisis computacionalmente indecidibles:
Sin embargo, también existe una tercera estrategia que a veces es aplicable para lenguajes que no están completamente especificados, como C. Un compilador optimizador tiene la libertad de generar código que haga cualquier cosa en tiempo de ejecución (incluso se bloquee) si encuentra código fuente cuya semántica no esté especificada por el estándar de lenguaje en uso.
El objetivo del análisis del flujo de control es obtener información sobre qué funciones se pueden llamar en distintos puntos durante la ejecución de un programa. La información recopilada se representa mediante un gráfico de flujo de control (GFC), en el que los nodos son instrucciones del programa y los bordes representan el flujo de control. Al identificar bloques de código y bucles, un GFC se convierte en un punto de partida para las optimizaciones realizadas por el compilador.
El análisis de flujo de datos es una técnica diseñada para recopilar información sobre los valores en cada punto del programa y cómo cambian con el tiempo. Los compiladores suelen utilizar esta técnica para optimizar el código. Uno de los ejemplos más conocidos de análisis de flujo de datos es la comprobación de taint , que consiste en considerar todas las variables que contienen datos proporcionados por el usuario (que se consideran "contaminados", es decir, inseguros) y evitar que se utilicen hasta que se hayan desinfectado. Esta técnica se utiliza a menudo para evitar ataques de inyección SQL . La comprobación de taint se puede realizar de forma estática o dinámica.
La interpretación abstracta permite extraer información sobre la posible ejecución de un programa sin ejecutarlo realmente. Los compiladores pueden utilizar esta información para buscar posibles optimizaciones o para certificar un programa frente a determinadas clases de errores.
Los sistemas de tipos asocian tipos a programas que cumplen determinados requisitos. Su finalidad es seleccionar un subconjunto de programas de un lenguaje que se consideren correctos según una propiedad.
La comprobación de tipos se utiliza en programación para limitar cómo se utilizan los objetos de programación y qué pueden hacer. Esto lo hace el compilador o el intérprete . La comprobación de tipos también puede ayudar a prevenir vulnerabilidades al garantizar que un valor con signo no se atribuya a una variable sin signo. La comprobación de tipos se puede realizar de forma estática (en tiempo de compilación), dinámica (en tiempo de ejecución) o una combinación de ambas.
La información de tipo estático (ya sea inferida o proporcionada explícitamente por anotaciones de tipo en el código fuente) también se puede utilizar para realizar optimizaciones, como reemplazar matrices encapsuladas con matrices no encapsuladas.
Los sistemas de efectos son sistemas formales diseñados para representar los efectos que puede tener la ejecución de una función o método. Un efecto codifica lo que se está haciendo y con qué se está haciendo; normalmente se los denomina tipo de efecto y región de efecto , respectivamente. [ Aclaración necesaria ]
La comprobación de modelos se refiere a formas estrictas, formales y automatizadas de comprobar si un modelo (que en este contexto significa un modelo formal de un fragmento de código, aunque en otros contextos puede ser un modelo de un fragmento de hardware) cumple con una especificación dada. Debido a la naturaleza inherente de estado finito del código, y a que tanto la especificación como el código se pueden convertir en fórmulas lógicas , es posible comprobar si el sistema viola la especificación utilizando métodos algorítmicos eficientes.
El análisis dinámico puede utilizar el conocimiento del tiempo de ejecución del programa para aumentar la precisión del análisis, al mismo tiempo que proporciona protección en tiempo de ejecución, pero solo puede analizar una única ejecución del problema y podría degradar el rendimiento del programa debido a las comprobaciones en tiempo de ejecución.
El software debe probarse para garantizar su calidad y que funcione como se espera de manera confiable y que no genere conflictos con otro software que pueda funcionar junto con él. Las pruebas se realizan ejecutando el programa con una entrada y evaluando su comportamiento y la salida producida. Incluso si no se especifican requisitos de seguridad, se deben realizar pruebas de seguridad adicionales para garantizar que un atacante no pueda manipular el software y robar información, interrumpir las operaciones normales del software o usarlo como pivote para atacar a sus usuarios.
La supervisión de programas registra distintos tipos de información sobre el programa, como el uso de recursos, los eventos y las interacciones, de modo que se pueda revisar para encontrar o señalar las causas de un comportamiento anormal. Además, se puede utilizar para realizar auditorías de seguridad. La supervisión automatizada de programas a veces se denomina verificación en tiempo de ejecución .
Para un subconjunto dado del comportamiento de un programa, la segmentación del programa consiste en reducir el programa a la forma mínima que aún produce el comportamiento seleccionado. El programa reducido se denomina "segmento" y es una representación fiel del programa original dentro del dominio del subconjunto del comportamiento especificado. Generalmente, encontrar un segmento es un problema irresoluble, pero al especificar el subconjunto del comportamiento objetivo mediante los valores de un conjunto de variables, es posible obtener segmentos aproximados utilizando un algoritmo de flujo de datos. Estos segmentos suelen ser utilizados por los desarrolladores durante la depuración para localizar la fuente de los errores.