stringtranslate.com

Análisis de tipo de estado

El análisis de estados de tipo , a veces llamado análisis de protocolo , es una forma de análisis de programas que se emplea en los lenguajes de programación . Se aplica más comúnmente a los lenguajes orientados a objetos . Los estados de tipo definen secuencias válidas de operaciones que se pueden realizar en una instancia de un tipo determinado. Los estados de tipo, como sugiere el nombre, asocian información de estado con variables de ese tipo. Esta información de estado se utiliza para determinar en tiempo de compilación qué operaciones son válidas para ser invocadas en una instancia del tipo. Las operaciones realizadas en un objeto que normalmente solo se ejecutarían en tiempo de ejecución se realizan sobre la información de estado de tipo que se modifica para que sea compatible con el nuevo estado del objeto.

Los estados de tipo son capaces de representar refinamientos de tipo de comportamiento como "el método A debe ser invocado antes de que se invoque el método B , y el método C no puede ser invocado entre medio". Los estados de tipo son adecuados para representar recursos que utilizan semántica de apertura/cierre al imponer secuencias semánticamente válidas como "abrir y luego cerrar" en lugar de secuencias no válidas como dejar un archivo en un estado abierto. Dichos recursos incluyen elementos del sistema de archivos, transacciones, conexiones y protocolos. Por ejemplo, los desarrolladores pueden querer especificar que los archivos o sockets deben abrirse antes de leerse o escribirse, y que ya no se pueden leer o escribir si se han cerrado. El nombre "estado de tipo" proviene del hecho de que este tipo de análisis a menudo modela cada tipo de objeto como una máquina de estados finitos . En esta máquina de estados, cada estado tiene un conjunto bien definido de métodos/mensajes permitidos, y las invocaciones de métodos pueden causar transiciones de estado. Las redes de Petri también se han propuesto como un posible modelo de comportamiento para su uso con tipos de refinamiento . [1]

El análisis de estado de tipo fue introducido por Rob Strom en 1983 [2] en el lenguaje de implementación de red (NIL) desarrollado en el Laboratorio Watson de IBM . Fue formalizado por Strom y Yemini en un artículo de 1986 [3] que describía cómo usar el estado de tipo para rastrear el grado de inicialización de las variables, garantizando que las operaciones nunca se aplicarían en datos inicializados incorrectamente, y fue generalizado en el lenguaje de programación Hermes .

En los últimos años, varios estudios han desarrollado formas de aplicar el concepto de estado de tipo a los lenguajes orientados a objetos. [4] [5]

Acercarse

Red de estados de tipo no lineal que surge de la inicialización de una variable de tipo struct{int x;int y;int z;}.
El elemento menor ⊥ coincide con el estado ∅ de ningún componente de estructura inicializado.

Strom y Yemini (1986) exigieron que el conjunto de estados de tipo para un tipo dado estuviera parcialmente ordenado de modo que se pueda obtener un estado de tipo inferior a partir de uno superior descartando alguna información. Por ejemplo, una intvariable en C normalmente tiene los estados de tipo " no inicializado " < " inicializado ", y un FILE*puntero puede tener los estados de tipo " no asignado " < " asignado, pero no inicializado " < " inicializado, pero archivo no abierto " < " archivo abierto ". Además, Strom y Yemini exigen que cada dos estados de tipo tengan un límite inferior máximo, es decir, que el orden parcial sea par un semirretículo de encuentro ; y que cada orden tenga un elemento mínimo, siempre llamado "⊥".

Su análisis se basa en la simplificación de que a cada variable v se le asigna solo un estado de tipo para cada punto en el texto del programa; si se llega a un punto p por dos rutas de ejecución diferentes y v hereda diferentes estados de tipo a través de cada ruta, entonces el estado de tipo de v en p se toma como el límite inferior máximo de los estados de tipo heredados. Por ejemplo, en el siguiente fragmento de código C, la variable nhereda el estado de tipo " initialized " y " uninitialized " de la parte theny la parte (vacía) else, respectivamente, por lo tanto, tiene el estado de tipo " uninitialized " después de toda la declaración condicional.

int n ; // aquí, n tiene typestate "sin inicializar" if (...) { n = 5 ; // aquí, n tiene typestate "sin inicializar" } else { /*no hacer nada*/ // aquí, n tiene typestate "sin inicializar" } // aquí, n tiene typestate "sin inicializar" = biggest_lower_bound("inicializado", "sin inicializar")             

Cada operación básica [nota 1] debe estar equipada con una transición de estado de tipo , es decir, para cada parámetro, el estado de tipo requerido y garantizado antes y después de la operación, respectivamente. Por ejemplo, una operación fwrite(...,fd)requiere fdtener el estado de tipo " archivo abierto ". Más precisamente, una operación puede tener varios resultados , cada uno de los cuales necesita su propia transición de estado de tipo. Por ejemplo, el código C FILE *fd=fopen("foo","r")establece fdel estado de tipo de en " archivo abierto " y " sin asignar " si la apertura tiene éxito y falla, respectivamente.

Para cada dos estados de tipo t 1 t 2 , se debe proporcionar una operación de conversión de estado de tipo única que, cuando se aplica a un objeto de estado de tipo t 2 , reduce su estado de tipo a t 1 , posiblemente liberando algunos recursos. Por ejemplo, fclose(fd)convierte fdel estado de tipo de " archivo abierto " a " inicializado, pero archivo no abierto ".

Se dice que la ejecución de un programa es correcta en cuanto a estado de tipo si

Se dice que un texto de programa es consistente con el estado de tipo si se puede transformar, mediante la adición de coerciones de estado de tipo adecuadas, en un programa cuyos puntos se pueden etiquetar estáticamente con estados de tipo de modo que cualquier camino permitido por el flujo de control sea correcto con el estado de tipo. Strom y Yemini ofrecen un algoritmo de tiempo lineal que verifica la consistencia del estado de tipo de un texto de programa dado y calcula dónde insertar qué operación de coerción, si corresponde.

Desafíos

Para lograr un análisis preciso y efectivo de los estados de los tipos, es necesario abordar el problema del aliasing . El aliasing ocurre cuando un objeto tiene más de una referencia o puntero que lo apunta. Para que el análisis sea correcto, los cambios de estado de un objeto determinado deben reflejarse en todas las referencias que apuntan a ese objeto, pero en general es un problema difícil rastrear todas esas referencias. Esto se vuelve especialmente difícil si el análisis necesita ser modular, es decir, aplicable a cada parte de un programa grande por separado sin tener en cuenta el resto del programa.

Como otro problema, para algunos programas, el método de tomar el límite inferior máximo en las rutas de ejecución convergentes y agregar las operaciones de coerción descendente correspondientes parece ser inadecuado. Por ejemplo, antes del return 1en el siguiente programa, [nota 3] se inicializan todos los componentes x, yy zof coord, pero el enfoque de Strom y Yemini no reconoce esto, ya que cada inicialización de un componente de estructura en el cuerpo del bucle tiene que ser coercionada descendentemente en la reentrada del bucle para cumplir con el estado de tipo de la primera entrada del bucle, es decir, ⊥. Un problema relacionado es que este ejemplo requeriría la sobrecarga de las transiciones de estado de tipo; por ejemplo, parse_int_attr("x",&coord->x)cambia un estado de tipo " ningún componente inicializado " a " componente x inicializado ", pero también " componente y inicializado " a " componente x e y inicializados ".

int parse_coord ( struct { intx ; inty ; intz ; } * coord ) { intseed = 0 ; /* recordar qué atributos han sido analizados * /                 mientras ( 1 ) si ( parse_int_attr ( "x" , & coord -> x )) visto |= 1 ; de lo contrario si ( parse_int_attr ( "y" , & coord -> y )) visto |= 2 ; de lo contrario si ( parse_int_attr ( "z" , & coord -> z )) visto |= 4 ; de lo contrario romper ;                        if ( seen != 7 ) /* falta algún atributo, falla */ return 0 ; ... /* todos los atributos presentes, realiza algunos cálculos y tiene éxito */ return 1 ; }          

Inferencia de estado de tipo

Existen varios enfoques que buscan inferir estados de tipos a partir de programas (o incluso otros artefactos como contratos). Muchos de ellos pueden inferir estados de tipos en tiempo de compilación [6] [7] [8] [9] y otros extraen los modelos dinámicamente. [10] [11] [12] [13] [14] [15]

Idiomas que admiten typestate

Typestate es un concepto experimental que aún no ha trascendido a los lenguajes de programación convencionales. Sin embargo, muchos proyectos académicos investigan activamente cómo hacerlo más útil como técnica de programación cotidiana. Dos ejemplos son los lenguajes Plaid y Obsidian, que están siendo desarrollados por el grupo de Jonathan Aldrich en la Universidad Carnegie Mellon . [16] [17] Otros ejemplos incluyen el marco de investigación del lenguaje Clara [18] , versiones anteriores del lenguaje Rust y la >>palabra clave en ATS . [19]

Véase también

Notas

  1. ^ Estos incluyen construcciones de lenguaje, por ejemplo +=en C, y rutinas de biblioteca estándar, por ejemplofopen()
  2. ^ Esto tiene como objetivo garantizar que, por ejemplo, todos los archivos se hayan cerrado y que mallocse haya freeutilizado toda la memoria ed. En la mayoría de los lenguajes de programación, la vida útil de una variable puede terminar antes de la finalización del programa; por lo tanto, la noción de corrección del estado de tipo debe afinarse en consecuencia.
  3. ^ asumiendo que int parse_int_attr(const char *name,int *val)se inicializa *valsiempre que tiene éxito

Referencias

  1. ^ Jorge Luis Guevara D´ıaz (2010). "Diseño orientado a estados tipográficos: un enfoque de redes de Petri coloreadas" (PDF) .
  2. ^ Strom, Robert E. (1983). "Mecanismos para la aplicación de la seguridad en tiempo de compilación". Actas del 10º simposio ACM SIGACT-SIGPLAN sobre Principios de lenguajes de programación - POPL '83 . págs. 276–284. doi :10.1145/567067.567093. ISBN 0897910907.S2CID6630704  .​
  3. ^ Strom, Robert E.; Yemini, Shaula (1986). "Typestate: Un concepto de lenguaje de programación para mejorar la confiabilidad del software" (PDF) . IEEE Transactions on Software Engineering . 12. IEEE: 157–171. doi :10.1109/tse.1986.6312929. S2CID  15575346.
  4. ^ DeLine, Robert; Fähndrich, Manuel (2004). "Typestates for Objects". ECOOP 2004 – Object-Oriented Programming . Apuntes de clase en informática. Vol. 3086. Springer. págs. 465–490. doi :10.1007/978-3-540-24851-4_21. ISBN 978-3-540-22159-3.
  5. ^ Bierhoff, Kevin; Aldrich, Jonathan (2007). "Comprobación modular del estado de los tipos de objetos con alias". Actas de la 22.ª conferencia anual ACM SIGPLAN sobre sistemas, lenguajes y aplicaciones de programación orientada a objetos . Vol. 42. págs. 301–320. doi :10.1145/1297027.1297050. ISBN 9781595937865.S2CID 9793770  .
  6. ^ Guido de Caso, Victor Braberman, Diego Garbervetsky y Sebastian Uchitel. 2013. Abstracciones de programas basadas en habilitación para validación de comportamiento. ACM Trans. Softw. Eng. Methodol. 22, 3, Artículo 25 (julio de 2013), 46 páginas.
  7. ^ R. Alur, P. Cerny, P. Madhusudan y W. Nam. Síntesis de especificaciones de interfaz para clases Java, 32.º Simposio ACM sobre principios de lenguajes de programación, 2005
  8. ^ Giannakopoulou, D., y Pasareanu, CS , "Generación de interfaz y verificación compositiva en JavaPathfinder", FASE 2009.
  9. ^ Thomas A. Henzinger, Ranjit Jhala y Rupak Majumdar. Interfaces permisivas. Actas del 13.º Simposio anual sobre fundamentos de la ingeniería de software (FSE), ACM Press, 2005, págs. 31-40.
  10. ^ Valentin Dallmeier, Christian Lindig, Andrzej Wasylkowski y Andreas Zeller. 2006. Minería del comportamiento de objetos con ADABU. En Actas del taller internacional de 2006 sobre análisis de sistemas dinámicos (WODA '06). ACM, Nueva York, NY, EE. UU., 17-24
  11. ^ Carlo Ghezzi, Andrea Mocci y Mattia Monga. 2009. Sintetización de modelos de comportamiento intensional mediante transformación de grafos. En Actas de la 31.ª Conferencia Internacional sobre Ingeniería de Software (ICSE '09). IEEE Computer Society, Washington, DC, EE. UU., 430-440
  12. ^ Mark Gabel y Zhendong Su. 2008. Minería simbólica de especificaciones temporales. En Actas de la 30.ª conferencia internacional sobre ingeniería de software (ICSE '08). ACM, Nueva York, NY, EE. UU., 51-60.
  13. ^ Davide Lorenzoli, Leonardo Mariani y Mauro Pezzè. 2008. Generación automática de modelos de comportamiento de software. En Actas de la 30.ª conferencia internacional sobre ingeniería de software (ICSE '08). ACM, Nueva York, NY, EE. UU., 501-510
  14. ^ Ivan Beschastnikh, Yuriy Brun, Sigurd Schneider, Michael Sloan y Michael D. Ernst. 2011. Aprovechamiento de la instrumentación existente para inferir automáticamente modelos con restricciones invariantes. En Actas del 19.º simposio ACM SIGSOFT y la 13.ª conferencia europea sobre fundamentos de la ingeniería de software (ESEC/FSE '11). ACM, Nueva York, NY, EE. UU., 267-277
  15. ^ Pradel, M.; Gross, TR, "Generación automática de especificaciones de uso de objetos a partir de grandes rastros de métodos", 2009. ASE '09. 24.ª Conferencia internacional IEEE/ACM sobre ingeniería de software automatizada, vol., n.º, págs. 371, 382, ​​16-20 de noviembre de 2009
  16. ^ Aldrich, Jonathan. "El lenguaje de programación Plaid" . Consultado el 22 de julio de 2012 .
  17. ^ Coblenz, Michael. "El lenguaje de programación Obsidian" . Consultado el 16 de febrero de 2018 .
  18. ^ Bodden, Eric. "Clara" . Consultado el 23 de julio de 2012 .
  19. ^ Xi, Hongwei. "Introducción a la programación en ATS" . Consultado el 20 de abril de 2018 .