stringtranslate.com

Ejecución simbólica

En informática , la ejecución simbólica (también evaluación simbólica o symbex ) es un medio de analizar un programa para determinar qué entradas hacen que se ejecute cada parte de un programa . Un intérprete sigue el programa, asumiendo valores simbólicos para las entradas en lugar de obtener entradas reales como lo haría la ejecución normal del programa. De este modo, llega a expresiones en términos de esos símbolos para expresiones y variables en el programa, y ​​restricciones en términos de esos símbolos para los posibles resultados de cada rama condicional. Finalmente, las posibles entradas que activan una rama se pueden determinar resolviendo las restricciones.

El campo de la simulación simbólica aplica el mismo concepto al hardware. La computación simbólica aplica el concepto al análisis de expresiones matemáticas.

Ejemplo

Considere el programa a continuación, que lee un valor y falla si la entrada es 6.

entero f () {   ... y = leer ();   z = y * 2 ;     si ( z == 12 ) {     fallar (); } demás {   printf ( "OK" ); }}

Durante una ejecución normal (ejecución "concreta"), el programa leería un valor de entrada concreto (por ejemplo, 5) y lo asignaría a y. Luego, la ejecución continuaría con la multiplicación y la rama condicional, que se evaluaría como falso e imprimiría OK.

Durante la ejecución simbólica, el programa lee un valor simbólico (por ejemplo, λ) y lo asigna a y. El programa luego procedería con la multiplicación y asignaría λ * 2a z. Al llegar a la ifdeclaración, evaluaría λ * 2 == 12. En este punto del programa, λpodría tomar cualquier valor y, por lo tanto, la ejecución simbólica puede continuar a lo largo de ambas ramas, "bifurcando" dos caminos. A cada camino se le asigna una copia del estado del programa en la instrucción de bifurcación, así como una restricción de ruta. En este ejemplo, la restricción de ruta es λ * 2 == 12para la iframa y λ * 2 != 12para la elserama. Ambos caminos se pueden ejecutar simbólicamente de forma independiente. Cuando las rutas terminan (por ejemplo, como resultado de la ejecución fail()o simplemente de la salida), la ejecución simbólica calcula un valor concreto para λal resolver las restricciones de ruta acumuladas en cada ruta. Estos valores concretos se pueden considerar como casos de prueba concretos que pueden, por ejemplo, ayudar a los desarrolladores a reproducir errores. En este ejemplo, el solucionador de restricciones determinaría que, para llegar a la fail()declaración, λnecesitaría ser igual a 6.

Limitaciones

Explosión de trayectoria

La ejecución simbólica de todas las rutas de programa factibles no es escalable para programas grandes. La cantidad de rutas factibles en un programa crece exponencialmente con el aumento del tamaño del programa e incluso puede ser infinita en el caso de programas con iteraciones de bucle ilimitadas. [1] Las soluciones al problema de explosión de rutas generalmente utilizan heurísticas para la búsqueda de rutas para aumentar la cobertura del código, [2] reducen el tiempo de ejecución mediante la paralelización de rutas independientes, [3] o mediante la fusión de rutas similares. [4] Un ejemplo de fusión es el veritesting , que "emplea la ejecución simbólica estática para amplificar el efecto de la ejecución simbólica dinámica". [5]

Eficiencia dependiente del programa

La ejecución simbólica se utiliza para razonar sobre un programa ruta por ruta, lo que es una ventaja sobre el razonamiento sobre un programa entrada por entrada como lo utilizan otros paradigmas de prueba (por ejemplo, el análisis dinámico de programas ). Sin embargo, si pocas entradas toman la misma ruta a través del programa, hay poco ahorro en comparación con probar cada una de las entradas por separado.

Alias ​​de memoria

La ejecución simbólica es más difícil cuando se puede acceder a la misma ubicación de memoria a través de diferentes nombres ( aliasing ). El aliasing no siempre se puede reconocer de forma estática, por lo que el motor de ejecución simbólica no puede reconocer que un cambio en el valor de una variable también cambia el de la otra. [6]

Matrices

Dado que una matriz es una colección de muchos valores distintos, los ejecutores simbólicos deben tratar la matriz completa como un valor o tratar cada elemento de la matriz como una ubicación separada. El problema de tratar cada elemento de la matriz por separado es que una referencia como "A[i]" solo se puede especificar de forma dinámica, cuando el valor de i tiene un valor concreto. [6]

Interacciones con el medio ambiente

Los programas interactúan con su entorno realizando llamadas al sistema , recibiendo señales, etc. Pueden surgir problemas de coherencia cuando la ejecución llega a componentes que no están bajo el control de la herramienta de ejecución simbólica (por ejemplo, el núcleo o las bibliotecas). Considere el siguiente ejemplo:

int principal () { ARCHIVO * fp = fopen ( "doc.txt" );    ... si ( condición ) {   fputs ( "algunos datos" , fp );  } demás {   fputs ( "algunos otros datos" , fp );  } ... datos = fgets (..., fp );   }

Este programa abre un archivo y, en función de una condición, escribe distintos tipos de datos en el archivo. Luego, vuelve a leer los datos escritos. En teoría, la ejecución simbólica bifurcaría dos rutas en la línea 5 y cada ruta a partir de allí tendría su propia copia del archivo. Por lo tanto, la instrucción en la línea 11 devolvería datos que son consistentes con el valor de "condición" en la línea 5. En la práctica, las operaciones de archivo se implementan como llamadas del sistema en el núcleo y están fuera del control de la herramienta de ejecución simbólica. Los principales enfoques para abordar este desafío son:

Ejecución directa de llamadas al entorno. La ventaja de este enfoque es que es fácil de implementar. La desventaja es que los efectos secundarios de dichas llamadas afectarán todos los estados administrados por el motor de ejecución simbólica. En el ejemplo anterior, la instrucción en la línea 11 devolvería "algunos datosalgunos otros datos" o "algunos otros datosalgunosdatos" según el orden secuencial de los estados.

Modelado del entorno. En este caso, el motor instrumenta las llamadas del sistema con un modelo que simula sus efectos y que guarda todos los efectos secundarios en un almacenamiento por estado. La ventaja es que se obtendrían resultados correctos al ejecutar simbólicamente programas que interactúan con el entorno. La desventaja es que es necesario implementar y mantener muchos modelos potencialmente complejos de llamadas del sistema. Herramientas como KLEE, [7] Cloud9 y Otter [8] adoptan este enfoque implementando modelos para operaciones del sistema de archivos, sockets, IPC , etc.

Bifurcación del estado completo del sistema. Las herramientas de ejecución simbólica basadas en máquinas virtuales resuelven el problema del entorno bifurcando el estado completo de la máquina virtual. Por ejemplo, en S2E [9] cada estado es una instantánea de la máquina virtual independiente que se puede ejecutar por separado. Este enfoque alivia la necesidad de escribir y mantener modelos complejos y permite ejecutar simbólicamente prácticamente cualquier binario de programa. Sin embargo, tiene mayores gastos generales de uso de memoria (las instantáneas de la máquina virtual pueden ser grandes).

Herramientas

Versiones anteriores de las herramientas

  1. EXE [11] es una versión anterior de KLEE. El documento sobre EXE se puede encontrar aquí.

Historia

El concepto de ejecución simbólica se introdujo académicamente en la década de 1970 con descripciones de: el sistema Select, [12] el sistema EFFIGY, [13] el sistema DISSECT, [14] y el sistema de Clarke. [15]

Véase también

Referencias

  1. ^ Anand, Saswat; Patrice Godefroid; Nikolai Tillmann (2008). "Ejecución simbólica compositiva impulsada por la demanda". Herramientas y algoritmos para la construcción y análisis de sistemas . Apuntes de clase en informática. Vol. 4963. págs. 367–381. doi :10.1007/978-3-540-78800-3_28. ISBN 978-3-540-78799-0.
  2. ^ Ma, Kin-Keng; Khoo Yit Phang; Jeffrey S. Foster; Michael Hicks (2011). "Ejecución simbólica dirigida". Actas de la 18.ª Conferencia internacional sobre análisis estadístico . Springer. págs. 95-111. ISBN. 9783642237010. Recuperado el 3 de abril de 2013 .
  3. ^ Staats, Matt; Corina Pasareanu (2010). "Ejecución simbólica paralela para la generación de pruebas estructurales". Actas del 19.° Simposio Internacional sobre Pruebas y Análisis de Software . págs. 183-194. doi :10.1145/1831708.1831732. hdl :11299/217417. ISBN. 9781605588230.S2CID 9898522  .
  4. ^ Kuznetsov, Volodymyr; Kinder, Johannes; Bucur, Stefan; Candea, George (1 de enero de 2012). "Fusión eficiente de estados en ejecución simbólica". Actas de la 33.ª Conferencia ACM SIGPLAN sobre diseño e implementación de lenguajes de programación . Nueva York, NY, EE. UU.: ACM. pp. 193–204. CiteSeerX 10.1.1.348.823 . doi :10.1145/2254064.2254088. ISBN .  978-1-4503-1205-9.S2CID 135107  .
  5. ^ "Mejora de la ejecución simbólica con Veritesting". Junio ​​de 2016.
  6. ^ ab DeMillo, Rich; Offutt, Jeff (1991-09-01). "Generación automática de datos de prueba basada en restricciones". IEEE Transactions on Software Engineering . 17 (9): 900–910. doi :10.1109/32.92910.
  7. ^ Cadar, Cristian; Dunbar, Daniel; Engler, Dawson (1 de enero de 2008). "KLEE: Generación automática y sin asistencia de pruebas de alta cobertura para programas de sistemas complejos". Actas de la 8.ª Conferencia USENIX sobre diseño e implementación de sistemas operativos . OSDI'08: 209–224.
  8. ^ Turpie, Jonathan; Reisner, Elnatan; Foster, Jeffrey; Hicks, Michael. "MultiOtter: Ejecución simbólica multiproceso" (PDF) .
  9. ^ Chipounov, Vitaly; Kuznetsov, Volodymyr; Candea, George (1 de febrero de 2012). "La plataforma S2E: diseño, implementación y aplicaciones". ACM Trans. Comput. Syst . 30 (1): 2:1–2:49. doi :10.1145/2110356.2110358. ISSN  0734-2071. S2CID  16905399.
  10. ^ Sharma, Asankhaya (2014). "Explotación de comportamientos indefinidos para una ejecución simbólica eficiente". ICSE Companion 2014: Actas complementarias de la 36.ª Conferencia internacional sobre ingeniería de software . págs. 727–729. doi :10.1145/2591062.2594450. ISBN . 9781450327688.S2CID10092664  .​
  11. ^ Cadar, Cristian; Ganesh, Vijay; Pawlowski, Peter M.; Dill, David L.; Engler, Dawson R. (2008). "EXE: Generación automática de entradas de muerte". ACM Trans. Inf. Syst. Secur . 12 : 10:1–10:38. doi :10.1145/1455518.1455522. S2CID  10905673.
  12. ^ Robert S. Boyer y Bernard Elspas y Karl N. Levitt SELECT: un sistema formal para probar y depurar programas mediante ejecución simbólica, Actas de la Conferencia Internacional sobre Software Confiable, 1975, páginas 234-245, Los Ángeles, California
  13. ^ James C. King, Ejecución simbólica y prueba de programas, Communications of the ACM, volumen 19, número 7, 1976, 385--394
  14. ^ William E. Howden, Experimentos con un sistema de evaluación simbólica, Actas, Conferencia Nacional de Computación, 1976.
  15. ^ Lori A. Clarke, Un sistema de prueba de programas, ACM 76: Actas de la Conferencia Anual, 1976, páginas 488-491, Houston, Texas, Estados Unidos

Enlaces externos