draft en pdf - Universidad Católica de Santiago del Estero

Transcripción

draft en pdf - Universidad Católica de Santiago del Estero
Draft – www.ucse.edu.ar/fma/~svcavadini/
Catálogo y análisis de Herramientas de Slicing
Juan José Tamagnini
[email protected]
Salvador Valerio Cavadini
[email protected]
Centro de Investigación y Desarrollo de Software (CIDESOFT)
Facultad de Matemática Aplicada
Universidad Católica de Santiago del Estero (Argentina)
Abstract
Con el objeto de facilitar la comprensión del estado del arte de las herramientas de slicing se
presenta una descripción y comparación de casi una veintena de ellas. Para la comparación de
los slicers se utiliza el criterio propuesto por Hoffner.
1 Introducción
El cálculo manual de slices [Wei84] es una compleja tarea que demanda gran
cantidad de tiempo y esfuerzo. Afortunadamente es posible desarrollar software que
calcule slices de programas en forma automática. A estas aplicaciones se las
denomina slicers.
Dado un programa fuente y un criterio de slicing, un slicer tiene que devolver
como resultado el conjunto de sentencias que conforman el slice correspondiente a
ese criterio. Para lograrlo, deben leer el programa fuente, representarlo internamente
usando alguna estructura de datos, calcular el slice sobre esta estructura y finalmente
mostrar al usuario el slice resultante.
Desde la óptica de los compiladores y traductores, un slicer es un traductor de
lenguaje fuente de alto nivel a lenguaje objeto de alto nivel [Ven91]. Más
precisamente, su entrada es un programa en algún lenguaje de alto nivel y su salida
un conjunto de sentencias –posiblemente un programa- en el mismo lenguaje.
Si se analizan con un poco más de detalle las funciones de un slicer, se lo
podría catalogar en general como un caso particular de los Analizadores Estáticos de
Programas (SPA, de Static Program Analizer, en inglés) [Jar98]. Los SPA son
herramientas interactivas que facilitan el entendimiento de programas durante la fase
de mantenimiento, ya que son capaces de responder a diferentes consultas sobre los
programas. Dependiendo de la tarea de mantenimiento que se tenga en mente, un
SPA debe procesar diferentes programas fuentes y contestar distintos tipos de
queries, extrayendo automáticamente vistas de programas. La Figura 1 muestra la
arquitectura general de un SPA.
Draft – www.ucse.edu.ar/fma/~svcavadini/
Draft – www.ucse.edu.ar/fma/~svcavadini/
programador
programa fuente
interface de usuario
vista del programa
query
SPA
front-end
Base de Conocimiento
del Sistema
evaluación de
query
Figura 1
Los principales componentes de un SPA son el front-end, el componente de
evaluación de queries, la interface de usuario y la base de conocimiento del sistema.
El front-end realiza el parsing del programa fuente y lo convierte en una
representación intermedia (RI) que queda almacenada en la base de conocimiento del
sistema. Un componente de interface con el usuario permite al programador-usuario
ingresar consultas y obtener las vistas como respuesta.
2 Catálogo
Durante la primera etapa del proyecto se tomó conocimiento de la existencia de
algunas herramientas de slicing desarrolladas por grupos de investigación
independientes y se obtuvieron algunas referencias y escasa documentación sobre
algunas de ellas. En la segunda etapa se procuró conseguir y completar la
documentación de la totalidad de las mismas, además de concentrar esfuerzos en pos
de detectar la existencia de otras herramientas relacionadas con estas novedosas
técnicas de análisis de programas. Estas actividades planeadas rindieron sus frutos:
se detectó la existencia de aproximadamente una veintena de herramientas enfocadas
al slicing de programas o relacionadas directa o indirectamente con esta técnica.
La cantidad y calidad de la información obtenida varía en cada caso. De algunas
herramientas sólo se logró saber que existen -o están en proceso de desarrollomientras que de otras se obtuvo abundante documentación, demos y hasta los
manuales de usuario. En la siguiente tabla se presenta una enumeración de las
mismas junto con la URL de los sitios de cada una de ellas. También se indica, para
cada caso, la disponibilidad de información.
Herramienta
CodeSurfer
GHINSU
URL
http://www.codesurfer.com/products/codesurfer/
codesurfer.html
http://www.softlab.ece.ntua.gr/research/research_p
rojects/Ghinsu/
Draft – www.ucse.edu.ar/fma/~svcavadini/
1
Información
Sí
Sí
Draft – www.ucse.edu.ar/fma/~svcavadini/
Herramienta
Oberon Slicing Tool
Project
Spyder
UNRAVEL
VALSOFT
VDGomatic
Wisconsin ProgramSlicing Tool
xSuds
SeeSlice
Surgeon
Slash (Kamkar's slicing
tool)
Schatz's slicing tool
FOCUS
ChopShop
PELAS
Menagerie
Microsoft's slicing tool
VisualAge for Cobol
URL
http://www.ssw.uni-linz.ac.at/Staff/CS/Slicing.html
http://www.brunel.ac.uk/~csstmmh2/researchprojects.html
http://www.cerias.purdue.edu/homes/spaf/spyder.ht
ml
http://hissa.ncsl.nist.gov/sw_assurance/cat.html
http://www.cs.tu-bs.de/softech/valsoft/
No disponible
http://www.cs.wisc.edu/wpis/html
Información
Sí
Sí
Sí
Sí
Sí
Sí
Sí
http://xsuds.argreenhouse.com/
No disponible
http://www.cs.loyola.edu/~kbg/Surgeon/
No disponible
Sí
Sí
Sí
Sí
No disponible
No disponible
http://www.cs.cmu.edu/afs/cs.cmu.edu/project/
chopshop/pub/www/home.html
No disponible
http://www.research.ibm.com/patv/
No disponible
http://www.research.ibm.com/patv/
Sí
Sí
No
No
No
No
No
En la mayoría de los casos la información proviene de los reportes producidos
por los mismos autores de las herramientas. Estas publicaciones se encuentran
disponibles en revistas especializadas, en Internet -vía ftp o http- o deben solicitarse
exclusivamente por e-mail.
Gran parte de las herramientas son el resultado de tesis doctorales o son
prototipos generados en el marco de proyectos de investigación relacionados con la
problemática del análisis y comprensión de programas, debugging, testing,
reusabilidad, representaciones intermedias, etc. Muy pocas son productos
comerciales. Esto se debe a que estos slicers han sido desarrollados, en general, con
propósitos de investigación y chequeo de algoritmos, demostración de viabilidad de
los enfoques y, casi todos ellos, se encuentran en estado de prototipos. A
continuación se describen brevísimamente las características más relevantes de los
proyectos y las herramientas involucradas.
!" UNRAVEL: es un prototipo de una herramienta CASE diseñada para asistir,
mediante el uso de slices, actividades relacionadas con la evaluación de software
escrito en ANSI C. Este proyecto se llevó adelante en el Instituto Nacional de
Estándares Tecnológicos de EE.UU. (NIST) por encargo de la Comisión
Reguladora Nuclear de EE.UU. (NRC) y el Sistema Nacional de Comunicaciones
de EE.UU. (NCS). Participan en el proyecto destacados investigadores, como
James R. Lyle, Dolores R. Wallace, James R. Graham, Keith B. Gallagher, Joseph
P. Poole y David W. Binkley. [LWG+95].
Actualmente el prototipo es capaz de calcular slices estáticos backward
ejecutables y puede utilizarse para evaluar estáticamente sistemas escritos en
ANSI C. Puede computar algunas operaciones sobre los slices obtenidos, tales
como intersección, unión y dice [Lyl84]. Su diseño permitiría que, en el futuro,
pueda dotarse a la herramienta con la capacidad para analizar otros lenguajes.
Draft – www.ucse.edu.ar/fma/~svcavadini/
2
Draft – www.ucse.edu.ar/fma/~svcavadini/
El código fuente de Unravel -aproximadamente 55.000 líneas de ANSI C sin
considerar comentarios- y abundante información sobre la herramienta, incluyendo
un manual de usuario, se obtuvo gratuitamente del sitio web.
!" GHINSU: Es el prototipo de un "entorno" para el análisis de programas ANSI C
desarrollado en el Departamento de Ciencias de la Computación y la Información
de la Universidad de Florida por un equipo de trece personas dirigidas por Panos
E. Livadas y Stephen Croll. La investigación contó con el soporte técnico y
económico (US$ 257.967 desde el año 1990 al 1995) del Florida/Purdue Software
Engineering Research Center -financiado a su vez por la National Science
Foundation-, el Center's 15 Industrial Affiliates y el Florida High Technology and
Industry Council.
Luego de dos años y medio de trabajo vio la luz un primer prototipo capaz de
realizar slicing, dicing, análisis ripple, análisis de dependencia, cálculo de cadenas
def-use (todos los usos que pueden realizarse con respecto a una definición) y
cadenas use-def (todas las definiciones que pueden alcanzar un determinado
uso).
Acepta como entrada programas escritos en un subconjunto de ANSI C -o Pascal,
aunque el soporte para este lenguaje se discontinuó luego de la primera versióndel que quedaron excluidas las asignaciones a punteros, la sentencia goto y las
sentencias break y continue. Además, sólo puede analizar programas que
constan de un solo archivo. Según reportes de sus diseñadores [LA94]
[LC94][LJ95][LR94], el prototipo inicial fue extendido para superar sus limitaciones,
principalmente aquellas relacionadas con las sentencias no aceptadas en el
sublenguaje de entrada.
Los profundos y complicados cambios que debían efectuarse a los efectos de
contemplar las sentencias de salto no estructurado y el manejo de punteros,
impulsaron a encarar un proceso de reingeniería sobre la herramienta. El nuevo
equipo de cinco personas que acometió el desafío adoptó el paradigma de diseño
orientado a objetos y el lenguaje de programación C++.
!" WISCONSIN PROGRAM-SLICING TOOL (WPST): Es el prototipo de una
herramienta para slicing de programas capaz de calcular tanto slices backward
como slices forward de programas ANSI C. Es desarrollado en la Universidad de
Wisconsin con el apoyo de la National Science Foundation de EE.UU. (NSC),
Defense Advanced Research Projects Agency de EE.UU., Argonne National
Laboratories, Cray Research Foundation, DEC, Eastman Kodak, HP, IBM, 3M y
Xerox. El equipo de proyecto está conformado por distinguidos investigadores
como Thomas Reps, Susan Horwitz, Geneviève Rosay, Samuel Bates, Marc
Shapiro, David Binkley y Thomas Ball, entre otros.
Este proyecto investiga la utilidad del slicing de programas como soporte en
operaciones de manipulación de programas (integración, diferenciación,etc.).
WPST soporta distintas operaciones sobre programas C, entre las que se incluyen
slicing backward, slicing forward y chopping [Rep93].
!" Oberon Slicing Tool (OST): En el Institut für Praktische Informatik
(Systemsoftware) de la Universidad Johannes Kepler de Linz, Austria, Christoph
Steindl desarrolló un slicer al que llamó OST [Ste98a][Ste98b]. Es capaz de
calcular slices estáticos backward o forward sobre programas orientados a objetos
Draft – www.ucse.edu.ar/fma/~svcavadini/
3
Draft – www.ucse.edu.ar/fma/~svcavadini/
-aunque también soporta programas estructurados- escritos en el lenguaje de
programación Oberon-2.
La herramienta cuenta con la potencia suficiente para tratar con todas las
particularidades de ese lenguaje: tipos estructurados, registros, arreglos, variables
globales, procedimientos anidados, objetos en el heap, recursión, punteros a
función, métodos, herencia, polimorfismo, etc.
!" CodeSurfer: Esta herramienta es la versión extendida y comercial de la WPST.
Su desarrollo es llevado a cabo por la compañía GrammaTech dentro de su línea
de "Software Analysis and Understanding Tools" y es presentada como "Una
nueva manera de analizar, navegar y entender código fuente". Este slicer usa
tecnología patentada de representación y slicing. Según los desarrolladores, esta
tecnología, probablemente la más avanzada del mercado, es capaz de detectar
automáticamente características del código fuente que otras herramientas de
análisis no descubren.
!" Spyder: Diseñada con el objeto de asistir a los programadores en las tareas de
debugging, Spyder incluye la exploración de nuevos métodos de backtracking en
la ejecución de programas, slicing dinámico y heurísticas de slicing, entre otras
técnicas. Es parte fundamental de un proyecto de investigación llevado a cabo por
la Universidad de Purdue (EE.UU.) sobre técnicas avanzadas de debugging.
Apadrinados por la National Science Foundation (NSF), participaron en este
proyecto importantes investigadores como Richard DeMillo, Gene Spafford, Hiralal
Agrawal y Hsin Pan.
El motivo principal del desarrollo de Spyder fue demostrar la utilidad del
paradigma de debugging basado en slicing-guessing-backtracking propuesto por
Agrawal [Agr91]. En la actualidad la herramienta puede utilizarse para realizar,
entre otras, slicing estático y dinámico, slicing de datos y slicing de control sobre
programas ANSI C.
!" XSuds: es un conjunto de herramientas diseñadas especialmente para asistir en
las tareas de análisis, comprensión, debugging y testing general de software. Esta
"suite" fue desarrollada en el Laboratorio de Investigación Aplicada de Bellcore, y
está disponible en http://www.xsuds.com como el "Sistema para entendimiento de
Software xSuds” y desde IBM como "Suite de herramientas IBM para testing y
Mantenimiento de programas C y C++".
El sistema es capaz de analizar el comportamiento dinámico de un software y
visualizar toda la información relevante a través de una interface gráfica integrada.
En esta herramienta se integraron las ideas aplicadas en las herramientas ATAC
[HLL94] y Spyder.
!" VALSOFT Slicing System: Es un conjunto de herramientas desarrolladas para
ayudar a comprender y validar código fuente escrito en lenguaje C. Su principal
aplicación es el cálculo y visualización de slices para ANSI C. El proyecto se lleva
a cabo desde 1995 en forma conjunta entre la Technical University of
Braunschweig y el Physikalisch-Technische-Bundesantstalt (PTB), ambos de
Alemania.
!" Proyecto Project: Es un proyecto de investigación, desarrollo e implementación
de herramientas para el análisis de programas basadas en métricas, slicing y
Draft – www.ucse.edu.ar/fma/~svcavadini/
4
Draft – www.ucse.edu.ar/fma/~svcavadini/
transformación de programas, llevado adelante en la Escuela de Computación de
la Universidad de North London. Participan importantes investigadores como Mark
Harman, Sebastian Danicic, Barry Jones, Bala y Yoga Sivagurunathan, que
enfocan a las tareas de análisis de código fuente como una actividad interactiva
basada en un diálogo tipo pregunta-respuesta, donde el programador realiza una
pregunta a una herramienta CASE y ésta debe responder produciendo una versión
simplificada del programa denominada proyección (de ahí el nombre del proyecto)
[HDJ+95]. Denominan proyección de un programa a una versión simplificada del
programa que mantiene una equivalencia semántica con el original. Esta definición
es una generalización de la original definición de slice -estático- de programas
presentada por Weiser, en la que se relaja la restricción que establece que el slice
debe ser un subconjunto del programa desde el cual se lo construye.
!" VDGomatic: Esta herramienta de slicing de programas en lenguaje C fue
diseñada y desarrollada en 1994 por Michael D. Ernst, un investigador de
Microsoft. Entre otras interesantes y potentes funciones, el slicer acepta la entrada
del usuario vía clicks del mouse y visualiza slices backward de clausura -intra o
interprocedurales- iluminando las porciones correspondientes del programa en el
editor del programador.
Este slicer utiliza al Value Dependence Graph (VDG) como representación
intermedia [WEC+94]. La idea subyacente en el diseño del VDG es que lo que
realmente importa son los valores calculados por lo programas, por lo tanto, los
nombres originales de las variables y el flujo o dependencias de control no se
representan. El autor propone integrar el slicer con un compilador que use al VDG
como representación intermedia en lugar de las otras representaciones
convencionales tales como el AST o el CFG. De esta manera, no sólo desaparece
la necesidad de desarrollar un front-end particular para el slicer, sino que además
se podría fácil y eficientemente generar código a partir de un slice, que no es otra
cosa que un VDG de menor -o a lo sumo igual- tamaño que el original. Siguiendo
siempre esta línea de razonamiento, Ernst introduce otro concepto novedoso: el
cálculo de slices sobre código optimizado [Ern94]. Propone cambiar la fuente de
información del algoritmo de slicing -el código fuente 'crudo'- por otra más precisa:
código optimizado (aquel que ya fue analizado, transformado y representado de
alguna manera) por un compilador optimizador.
!" Slicer de Comprehensive Health Care System (CHCS): Este slicer fue
desarrollado por el Departamento de Ciencias de la Computación e Ingeniería de
la Universidad de California (EE.UU.) conjuntamente con la Science Applications
International Corporation (SAIC). En el proyecto participaron, entre otros, Darren
Atkinson y William Griswold [AG96]. Fue diseñado específicamente para ayudar a
comprender el código de un único programa: el Comprehensive Health Care
1
System (CHCS), un sistema de administración de hospitales .
!" Surgeon's Assistant Tool: Es una herramienta especialmente diseñada para
quienes programan o realizan mantenimiento de programas ANSI C. Permite aislar
los componentes estables o fijos -que no requieren cambios- de aquellos que
requieren modificaciones o adaptaciones. Para lograrlo, divide al programa en
unidades de descomposición, que son slices ejecutables. Las variables del
programa también se separan conformando dos grupos: las que cambian y las que
1
El CHCS es un programa de un millón de líneas escrito en MUMPS, un lenguaje interpretado con sintaxis muy similar
a la de BASIC.
Draft – www.ucse.edu.ar/fma/~svcavadini/
5
Draft – www.ucse.edu.ar/fma/~svcavadini/
no. El usuario cuenta con información sobre las diferentes interacciones entre los
componentes de ambos grupos. La herramienta impide que los cambios aplicados
en los elementos suceptibles de ser modificados impacten sobre los fijos. De esta
manera las adaptaciones pueden realizarse de una manera consistente.
Los slices estáticos ejecutables que produce la herramienta también pueden
considerarse como candidatos para incorporarse en bibliotecas de componentes
reusables, como esqueletos para la construcción de nuevo código, para
actividades de comprensión y abstracción de programas y para re-ingeniería e
ingeniería reversa. Lamentablemente, sólo se encontró una descripción muy
general de esta interesante herramienta.
!" Kamkar's slicing tool: Diseñada con el objeto de evaluar ciertos algoritmos
definidos por Mariam Kamkar, las áreas de aplicación pretendidas para la
herramienta son las relacionadas con el testing y el debugging. El slicer,
desarrollado en el Departamento de Ciencias de la Computación y la Información
de la Universidad de Linköping, Suecia, calcula slices backward dinámicos
interprocedurales, y sólo puede procesar programas escritos en un subconjunto
del lenguaje Pascal. Unicamente pueden usarse variables de tipo entero o
caracter, que pueden ser escalares, vectores o matrices. No soporta funciones.
!" Schatz’s slicing tool: Este slicer es una implementación con propósitos de
investigación basado en el trabajo de Ottenstein y Ottenstein sobre PDG [OO84].
Trabaja en combinación con el asistente interactivo para paralelización PAT
(Parallelizing Assistant Tool) y es capaz de procesar programas codificados en un
subconjunto de FORTRAN. La herramienta calcula slices estáticos backward
intraprocedurales. El algoritmo de slicing está basado en uno de alcance en PDG.
!" FOCUS: Este slicer, versión actualizada de un debugger homónimo, calcula slices
estáticos backward intraprocedurales, aunque a los efectos de asistir a las
actividades de debugging, también es capaz de realizar dicing. Sólo puede
procesar programas escritos en un subconjunto del lenguaje C. No soporta
punteros ni llamados a funciones.
!" SeeSlice:Tomas Ball y Stephen G. Eick de los Laboratorios AT&T de Bell
desarrollaron esta herramienta que construye el grafo de dependencia dinámica de
la ejecución de un programa y permite obtener slices backward y forward. No se
encontraron mayores detalles sobre este slicer, ya que presumiblemente sólo fue
construido con el objeto de experimentar con técnicas de visualización de slices.
2 Comparación de herramientas de slicing
No existe un criterio establecido acerca de cómo evaluar herramientas de slicing.
El reporte de Hoffner [Hof95] compara distintas características de algunos sistemas de
slicing existentes con el propósito de obtener conclusiones sobre la aplicabilidad de los
diferentes enfoques que emplea cada uno de ellos.
En su reporte, Hoffner sostiene que no hay manera de comparar herramientas
de slicing y obtener resultados del tipo la herramienta A es mejor que la B si no se
establece previamente un conjunto de criterios o presunciones que restrinjan el
análisis. Bajo estos considerandos, define cuatro cualidades básicas que debería
poseer una buena herramienta de slicing:
Draft – www.ucse.edu.ar/fma/~svcavadini/
6
Draft – www.ucse.edu.ar/fma/~svcavadini/
#" Generar slices correctos. Lo que se entiende por correcto depende
muchas veces del propósito para el cual el algoritmo fue diseñado. De todas
maneras, un slice es incorrecto si excluye algo que debería estar contenido
en el slice mínimo.
#" Generar slices relevantes. Dependiendo de la aplicación del slicer, un slice
es relevante si ayuda al usuario a enfocar su atención en las partes
relevantes del programa.
#" No restringir el uso del lenguaje fuente. La mayoría de los algoritmos de
análisis imponen restricciones sobre las características de los programas
que pueden analizar. Por ejemplo, hay muy pocos algoritmos que pueden
manejar correctamente la problemática relacionada con el aliasing y los
punteros.
#" Ser eficiente en el uso de tiempo y espacio. El cálculo de slices es un
proceso que está compuesto por varias fases. En el caso de los algoritmos
de slicing estático, las fases bien diferenciadas son la preparación del código
fuente y el cálculo de los slices. Además, lo que se ejecuta en cada fase
depende de los diferentes algoritmos, representaciones intermedias e
implementaciones. Para el caso de los algoritmos que extraen slices
dinámicos, debe adicionarse el tiempo de compilación y corrida del
programa.
Los requerimientos de espacio de memoria también constan de dos partes:
por un lado, se requiere espacio de memoria para procesar el programa
fuente, mientras que por otro lado debe considerarse el espacio requerido
por estructuras auxiliares, archivos temporarios, etc. utilizados por el
algoritmo de slicing.
Para poder comparar, considerando que las herramientas y los algoritmos
subyacentes están desarrollados para diferentes aplicaciones y utilizan diferentes
tipos de información, Hoffner sugiere clasificarlos según algunas características
esenciales, tanto de los algoritmos como de la implementación. A continuación se
describen brevemente los criterios propuestos por Hoffner.
Con respecto a los algoritmos:
$" Variable de slicing. Algunos algoritmos exigen que las variables del
criterio estén definidas o utilizadas en la sentencia del criterio, mientras
que otros permiten cualquier conjunto de variables del programa sin
ninguna otra restricción.
$" Tipo de slice. Si el algoritmo siempre produce slices ejecutables, se dice
que genera programas parcialmente equivalentes, caso contrario se
considera que produce conjuntos de sentencias.
$" Punto de slicing. El punto de slicing es la posición en el programa con
respecto al cual se calcula el slice. Este punto puede encontrarse
inmediatamente antes o inmediatamente después de la sentencia del
criterio, e influye en la pertenencia de la sentencia al slice.
$" Ambito (Scope) del slice. Se denominan algoritmos interprocedurales a
aquellos que pueden calcular el slicing a través de los procedimientos,
mientras que los intraprocedurales están limitados exclusivamente a los
Draft – www.ucse.edu.ar/fma/~svcavadini/
7
Draft – www.ucse.edu.ar/fma/~svcavadini/
límites de un procedimiento o función, ya que no toman en cuenta
llamados a procedimientos, paso de parámetros, etc.
$" Dirección del slicing. Dependiendo del sentido en que se recorra el
programa para calcular el slice, el algoritmo puede ser backward responde a la definición original de slicing- o forward.
$" Nivel de abstracción. Existen varios niveles de abstracción o
granularidad sobre los que puede trabajar un algoritmo de slicing. La
abstracción es a nivel de sentencia si considera a las sentencias como las
unidades básicas para la inclusión o no en el slice. Otros algoritmos
trabajan a nivel de procedimiento, y por lo tanto la unidad mínima que el
algoritmo incluye en un slice son procedimientos completos. El menor
nivel de abstracción lo logran los algoritmos que operan a nivel de
expresión, que manipulan directamente tokens.
$" Tipo de información. Si el algoritmo sólo se vale de información obtenida
en tiempo de compilación se denomina estático, mientras que si además
aprovecha información extra conseguida en tiempo de ejecución se lo
califica como dinámico.
$" Método de cálculo. El método original fue propuesto por Weiser, y
consiste en la solución de ecuaciones de flujo de datos. Posteriormente
aparecieron algoritmos que se basan en representaciones de grafos como
el PDG y el SDG. Estos enfoques consideran al slicing como un problema
de alcance -reachability- en grafos de dependencia.
Con respecto a la implementación:
$" Area de aplicación. En general, el área de aplicación determina
fuertemente el algoritmo de slicing. Por ejemplo, si se desea utilizar el
slicing como auxiliar del debugging, convendría que la herramienta arroje
slices dinámicos.
$" Lenguaje. El lenguaje para el cual la herramienta fue desarrollada puede
comprometer seriamente su generalidad.
$" Formato de salida. La manera en que la herramienta presenta los slices
(coloreado de código, grafo, árbol de ejecución, etc.) puede influir en la
comparación de resultados y utilización de los mismos.
En la comparación efectuada en este trabajo, no se consideraron los criterios
variable de slicing, punto de slicing y formato de salida, ya que no se cuenta, en la
gran mayoría de los casos, con información suficientemente precisa sobre estas
características. Además, con el objeto de cotejar las plataformas requeridas para
poder correr las herramientas, se incorpora un nuevo criterio relacionado con la
implementación, al que se ha denominado plataforma.
El siguiente cuadro resume la comparación realizada. No se incluyen en él las
herramientas para las cuales no fue posible reunir información suficiente.
Draft – www.ucse.edu.ar/fma/~svcavadini/
8
Draft – www.ucse.edu.ar/fma/~svcavadini/
Prueba de slicers
Con el objeto de constatar lo que sus autores afirman en los reportes y de
comprobar el potencial real de los slicers, se intentó por diversos medios conseguir las
herramientas o al menos sus demos. En algunos casos se bajaron versiones demos
desde sitios de Internet, en otros casos se trató de contactar a sus diseñadores.
Siempre que fue posible se solicitaron las aplicaciones a través de correspondencia
tradicional y/o e-mails.
En general, hasta el momento, los esfuerzos resultaron prácticamente
infructuosos. Las herramientas no están disponibles de manera gratuita, no existen
demos, no fue posible contactar a varios autores o no se cuenta con las plataformas
adecuadas para correrlas. Sin embargo, se obtuvo una versión demo de Project que
corre sobre D.O.S. y se instaló Unravel.
En lo que respecta a Project, se consiguió -vía ftp- un prototipo de la
herramienta que corre sobre D.O.S. El slicer acepta programas escritos en un
subconjunto del lenguaje de programación C y realiza slicing combinado con algunas
de las transformaciones que sus autores proponen en sus reportes. La herramienta
dispone de un ambiente de trabajo desde el cual se permite abrir y editar los
programas, seleccionar el criterio de slicing, efectuar transformaciones, obtener
métricas básicas del programa (variables globales, profundidad de anidamiento, tipo y
número de sentencias utilizadas) y ejecutar un traductor de C a Pascal. Durante el uso
de la herramienta, se pudo observar que el prototipo está en un estado primitivo de
desarrollo ya que en algunos casos de prueba se ‘colgaba’ irreversiblemente.
La aplicación Unravel fue descargada -también vía ftp- e instalada sobre un
sistema Linux Red Hat Linux 6.2 (Kernel 2.2.16) corriendo sobre un Pentium III 550,
128 MB RAM y 10 GB HD. Se ejecutaron numerosas pruebas pudiendo constatar lo
que los autores afirman en sus informes. Los manuales de usuario, muy completos, y
la interface desarrollada sobre X-windows KDE Desktop facilitaron el aprendizaje y
uso de la herramienta.
Draft – www.ucse.edu.ar/fma/~svcavadini/
9
Draft – www.ucse.edu.ar/fma/~svcavadini/
Cuadro Comparativo de Slicers
Slicer
UNRAVEL
Ghinsu
OST
WPST
CodeSurfer
Spyder
xSuds
VALSOFT
Project
Area
de
Aplicación
Revisión y
evaluación de
software
Comprensión de
software
No especificada
Asistencia en el
desarrollo de
software
Análisis y
comprensión de
software
Asistencia en
debugging
Análisis,
comprensión,
debugging y
testing de software
Validación y
comprensión de
software
Análisis y
comprensión de
software
VDGomatic
No
especificada
Slicer de
CHCS
Comprensión de
software
Surgeon’s
Assistant
Tool
Kamkar’s
Slicing Tool
Desarrollo y
mantenimiento
de software
Testing y
debugging de
software
Investigación
Schatz’s
Slicing Tool
FOCUS
Debugging
Alcanzabilidad
en grafos
C
Sentencia
Estática
Alcanzabilidad
en grafos
C
Backward
Sentencia
Sentencia
Alcanzabilidad
en grafos
N/D
C
Backward
Estática
Dinámica
Estática
Dinámica
Inter
procedural
Backward
Forward
Expresión
Estática
Alcanzabilidad
en grafos
C
Tipo
de
Inform.
Estática
Inter
procedural
Inter
procedural e
Intermodular
Inter
procedural
Backward
Forward
Backward
Forward
Expresión
Estática
Expresión
Estática
Backward
Forward
Sentencia
Solaris
Inter
procedural
Backward
Forward
UNIX
Inter
procedural
Inter
procedural
UNIX
Conjunto de
sentencias
Estática
Nivel
de
Abstracción
Sentencia
Conjunto de
sentencias
Conjunto de
sentencias
Conjunto de
sentencias
Conjunto de
sentencias
Lenguaje
Dirección
de
slicing
Backward
Plataforma
Conjunto de
sentencias
N/D
Conjunto de
sentencias
Método
de
Cálculo
Ecuaciones de
Flujo de
Datos
Alcanzabilidad
en grafos
Alcanzabilidad
en grafos
Ámbito
de
Slicing
Inter
procedural
Tipo
de
Slice
Ejecutable
UNIX
Oberon
System
UNIX
Windows 95
Linux
SunOS, AIX
HP-UX
N/D
C
C
Oberon-2
C
C++
Ejecutable
semánticamente
equivalente
Conjunto de
sentencias
Ejecutable
N/D
D.O.S.
Inter
procedural
Backward
Sentencia
Estática
N/D
C
N/D
Inter
procedural
Backward
Expresión
(operación)
Estática
Alcanzabilidad
en grafos
C
N/D
Inter
procedural
Backward
N/D
Estática
MUMPS
Ejecutable
UNIX
N/D
N/D
N/D
Estática
Ecuaciones de
Flujo de
Datos
N/D
Conjunto de
Sentencias
N/D
Inter
procedural
Backward
Procedimiento
Dinámica
Alcanzabilidad
en grafos
Pascal
N/D
N/D
Backward
N/D
Estática
N/D
Backward
N/D
Estática
Alcanzabilidad
en grafos
Ecuaciones de
Flujo de
Datos
FORTRAN
N/D
Intra
procedural
Intra
procedural
Draft – www.ucse.edu.ar/fma/~svcavadini/
C
C
Draft – www.ucse.edu.ar/fma/~svcavadini/
Slicer
SeeSlice
Area
de
Aplicación
Investigación
Tipo
de
Slice
Conjunto de
sentencias
Plataforma
N/D
Ámbito
de
Slicing
Inter
procedural
Dirección
de
slicing
Backward
Forward
11
Nivel
de
Abstracción
N/D
Tipo
de
Inform.
Dinámica
Método
de
Cálculo
N/D
Lenguaje
C
Draft – www.ucse.edu.ar/fma/~svcavadini/
3 Consideraciones Finales sobre las herramientas de slicing
Sería arriesgado afirmar que se encontraron todas las herramientas. Sin
embargo, las exhaustivas búsquedas realizadas en Internet, sumadas a la información
obtenida de la comunicación establecida con algunos autores e investigadores
comprometidos -desde hace varios años- en la temática del slicing, permiten afirmar
que los slicers descriptos constituyen un alto porcentaje de los slicers existentes y,
además, conforman una muestra muy representativa de los mismos.
Aunque la cantidad de herramientas localizadas y analizadas superó
ampliamente las expectativas iniciales, se deduce que son escasas, más aún si se
considera que la búsqueda se realizó a nivel mundial y si además se tiene en cuenta
la cantidad de herramientas de software en un estado maduro de desarrollo
pertenecientes a otras categorías tales como compiladores, debuggers, testers, etc.
Todos los slicers pueden considerarse de primera generación. La gran mayoría
se encuentra en estado de prototipos y son desarrollados principalmente con
propósitos de investigación, para la constatación empírica de ciertas hipótesis, análisis
de algoritmos, etc. En general, presentan restricciones de diversa índole; tienen
problemas de performance y soportan sólo subconjuntos de lenguajes.
Resulta impresionante la cantidad de recursos humanos, técnicos y económicos
invertidos en los proyectos de desarrollo de algunos slicers, como es el caso de
Unravel, Ghinsu y Wisconsin Program Slicing Tool. Gran parte de los emprendimiento
se llevan a cabo en ámbitos universitarios con la participación y/o apoyo técnico y
financiero de varias instituciones gubernamentales y poderosas organizaciones o
corporaciones relacionadas con la informática, algunas de ellas muy conocidas como
IBM, Microsoft, Hewlett Packard, Xerox, 3M, Kodak, DEC, Cray Research Foundation,
National Science Foundation de EE.UU.
2
Ninguna herramienta soporta más de un lenguaje . Sus diseñadores sostienen
que al estar basadas en una representación intermedia independiente del lenguaje
fuente, añadir la capacidad necesaria para soportar otros lenguajes sería una tarea
relativamente sencilla. Sin embargo, y sin negar lo anterior, pudo constatarse que
muchas decisiones de diseño y desarrollo contemplan fuertemente el lenguaje de
programación cuyos programas se pretenden analizar. Por ejemplo, el slicer de
Oberon aplica los algoritmos de [ASU86] para realizar el análisis de flujo de datos, los
cuales funcionan sin problemas si el lenguaje es estructurado pero requerirían
modificaciones drásticas si el lenguaje no gozase de tal propiedad. Otro tanto ocurre
con Spyder, que al estar imbuido dentro de un compilador y un debugger para C,
lograr que admita como entrada programas codificados en otro lenguaje fuente
equivale a desarrollar un slicer en su totalidad. Además es muy difícil, si no imposible,
conseguir que una herramienta que soporta lenguajes estructurados también acepte
los orientados a objetos y/o los funcionales sin que medien cambios importantes en la
arquitectura o la representación intermedia.
Casi todas las herramientas están diseñadas para procesar programas
procedurales codificados en un subconjunto especial de C, lo cual reafirma el amplio
dominio de este lenguaje en las aplicaciones existentes. Algunas pocas consideran o
han contemplado procesar programas en Pascal -Kamkar’s Slicing Tool y Ghinsu- y
sólo una de las estudiadas es capaz de calcular slices sobre lenguajes orientados a
objetos -slicer de Oberon-. Estos últimos lenguajes presentan una serie de problemas
2
Ghinsu discontinuó el soporte de Pascal después del primer prototipo.
Draft – www.ucse.edu.ar/fma/~svcavadini/
Draft – www.ucse.edu.ar/fma/~svcavadini/
adicionales tales como el polimorfismo y el enlace dinámico, los cuales los
transforman en poco aptos para que se los considere como entradas de prototipos de
slicers desarrollados con específicos propósitos de investigación. Por otra parte, no se
localizó ninguna herramienta que calcule slices sobre lenguajes funcionales.
Todos los reportes técnicos estudiados hacen referencia directa o
indirectamente al difícil problema que representa para las técnicas de slicing el
tratamiento de algunos aspectos tales como el flujo de control no estructurado, los
punteros y el aliasing, los tipos de datos compuestos y el análisis de datos
interprocedural, entre otros. La mayoría simplifica la problemática restringiendo el
dominio de los programas que son capaces de analizar de manera tal que resulten
excluidos todos aquellos que presentan alguna de estas situaciones. Muy pocos VDGomatic, CodeSurfer- encaran y solucionan con diferentes técnicas todas o
algunas de estas situaciones complejas.
Con respecto a la arquitectura interna de las herramientas se puede afirmar que
la gran mayoría de los investigadores ha centrado el diseño en una arquitectura tipo
pipes & filters [ACG+94], típica de los compiladores, conformada por los siguientes
componentes básicos:
$" Un front-end que analiza léxica y sintácticamente el programa y lo
transforma a una representación intermedia sobre la cual se calculan las
dependencias de control y de datos.
$" Una interface de usuario que se encarga de recibir las órdenes y de
presentar los resultados.
$" Un módulo que implementa el algoritmo de slicing, cuya función principal
es ejecutar las tareas encomendadas por el usuario a través de la
interface.
Ésta es, en términos generales, la arquitectura subyacente en la mayoría de las
herramientas analizadas. La diferencia más notable entre los diseños es el momento
en que se calculan las dependencias. Algunas lo hacen a medida que construyen la
representación intermedia mientras que otras postergan el cálculo hasta una vez
finalizada la construcción de la representación intermedia. En el front-end se
presentan otras diferencias de menor importancia que tienen que ver con la forma de
tratar las directivas de compilación y la técnica de parsing utilizada.
En lo que se refiere a la representación intermedia utilizada por las herramientas
analizadas, el PDG parece ser la dominante en los slicers. La mayoría de las
herramientas se apoya en él -o en alguna de sus múltiples variantes- como estructura
principal, y sus autores fundamentan la elección basándose en la eficiencia que logra
el algoritmo de slicing cuando el cálculo de los slices se mapea como un problema de
alcance en grafos. Sin embargo, construir de manera eficiente el PDG -más
estrictamente, el subgrafo de dependencia de control- se torna muy complejo cuando
el programa no es estrictamente estructurado. ¿Cómo solucionaron este problema si
el lenguaje que escogieron, por ejemplo C, permite codificar programas
desestructurados? De una manera muy simple: casi todas eliminan del sublenguaje
aceptado las sentencias goto, continue, break y, a veces, tampoco tratan bien
con cuestiones tales como alias, punteros y estructuras de datos complejas. Estas
restricciones impuestas ponen en duda su utilidad concreta en casos reales, ya que si
bien sólo el 3% de los programas modernos contienen sentencias goto [BM92] la
gran mayoría de los programas en lenguaje C presentan algún nivel de desestructura
Draft – www.ucse.edu.ar/fma/~svcavadini/ 14
Draft – www.ucse.edu.ar/fma/~svcavadini/
debido al uso de sentencias break y continue. Si además la herramienta está
orientada a ayudar en el proceso de comprensión de programas, su utilidad es aún
menor pues este tipo de tareas por lo general se efectúa sobre código escrito en
tiempos en que los programadores hacían un uso exhaustivo del goto debido a que
el paradigma de la programación estructurada no se había establecido totalmente.
Por otro lado, todas las interfaces se basan en ventanas, aunque cada
herramienta aprovecha de distinta manera las facilidades de visualización e
interacción que ofrecen los entornos gráficos. Con excepción de xSuds y CodeSurfer,
no se observa que los desarrolladores le hayan otorgado demasiada importancia al
diseño de las interfaces. Dos investigadores de los laboratorios Bell, Thomas Ball y
Stephen Eick en [BE94] y [BE96] han puesto sobre el tapete la problemática de la
visualización en herramientas que trabajan con programas de mediano y gran tamaño,
cuestionando la aptitud de las interfaces basadas solamente en browsers de texto o
editores dirigidos por la sintaxis en estos casos especiales.
Algunos diseñadores han utilizado otras herramientas de software para la
construcción de su slicer. Los conocidos compiladores de compiladores Lex [LS75] y
Yacc [Joh75] son muy empleados para la construcción de los front-end. Un caso
especial es Spyder, por ejemplo, que está imbuido en el GNU C Compiler y el GNU
Debugger. Como lo indican sus autores, este enfoque ahorra trabajo pues permite
aprovechar componentes de otras herramientas ya desarrolladas -y probadas- para
construir una nueva. Si bien esta aseveración es totalmente cierta, el reuso de estos
componentes puede afectar enormemente la capacidad de la herramienta para
soportar múltiples lenguajes fuentes como entrada.
La gran mayoría de las herramientas analizadas usan al sistema operativo UNIX
como plataforma de ejecución. xSuds es la única que se encuentra disponible para
ejecutarse en varios sistemas operativos, una característica cada vez más frecuente
en las herramientas modernas de software comerciales. Project es la única que corre
en DOS y OST, por otro lado, se ejecuta sobre Oberon System.
Sólo una cuarta parte de las herramientas analizadas calcula slices a nivel de
expresión; las demás lo hacen a nivel de sentencia y sólo una -Kamkar’s Slicing Toola nivel de procedimiento. El slicing a nivel de sentencias brinda información precisa si
las sentencias individuales no son demasiado complejas y no usan o definen muchas
variables. Si en cambio el lenguaje de entrada permite múltiples definiciones en
sentencias individuales, el uso de la expresión como unidad para el cálculo de los
slices deriva en una mejora en la precisión de los resultados. Como contrapartida, el
tamaño de la representación intermedia es mucho mayor con respecto a las utilizadas
por los slicers orientados a sentencia. La generación de slices sintácticamente válidos
también se complica al utilizar slicing orientado a expresiones. Todos los slicers
analizados que operan a nivel de expresión utilizan como representación intermedia al
AST o alguna combinación de AST con PDG.
La gran mayoría de los diseñadores de slicers han optado por calcular slices de
clausura, los cuales se pueden obtener más fácilmente que los slices ejecutables -o
sintácticamente válidos-. Esta elección se debe principalmente a dos razones:
primero, dado que las herramientas se encuentran en estado de prototipo se evitó
agregarles complejidad; segundo, las aplicaciones para las que están desarrollados
estos slicers no precisan que el resultado sea sintácticamente válido. Merece
destacarse VDGomatic pues es la única aplicación que calcula tanto slices de
clausura como ejecutables, éstos últimos a través de la generación de código nativo
en vez de código fuente sintácticamente correcto. Por su parte, el slicer Project es el
único que genera slices quasi-estáticos no restringidos sintácticamente, los cuales se
Draft – www.ucse.edu.ar/fma/~svcavadini/ 15
Draft – www.ucse.edu.ar/fma/~svcavadini/
obtienen como resultado de aplicar el algoritmo de slicing sobre código transformado.
Estos slices son semánticamente equivalentes pero generalmente más pequeños que
aquellos que se calculan desde el código fuente sin transformar.
Lo expuesto anteriormente facilita la comprensión del estado del arte de las
herramientas de slicing. En síntesis: un programador que ha escrito código en
lenguaje C sólo podrá elegir entre un par de slicers para que lo asistan en el desarrollo
del software. Esto contrasta con la amplia disponibilidad de compiladores,
optimizadores, debuggers, etc. que existen para programas escritos en C. Más aún, si
el programador no escribe su código en lenguaje C, sino que utiliza otro lenguaje
como Pascal, Modula, Ada, COBOL, etc., se verá privado de la posibilidad de hacer
uso de la tecnología de slicing por carecer de una herramienta apropiada.
Bibliografía y Referencias
ACG+94 ABD-ALLAH, Ahmed, CLARK, Bradford, GACEK, Cristina y BOEHM, Barry. Knowledge
Summary. USC Center for Software Engineering - Focused Workshop on Software
Architectures, USC (Los Angeles, CA) - 6 al 9 de Junio de 1994.
AG96 ATKINSON, Darren C. y GRISWOLD, William G. The Design of Whole-Program
Analysis Tool. En Proceedings of the 18th International Conference on Software
Engineering (ICSE-18), Berlin, Alemania, Marzo 1996.
Agr91 AGRAWAL, Hiralal. Towards Automatic Debugging of Computer Programs. Phd.
Thesis, Purdue University, Agosto 1991.
ASU86 AHO, Alfred V., SETHI, Ravi y ULLMAN, D. Jeffrey. Compilers: Principles, techniques
and tools. Addison Wesley,1986.
BE94 BALL, Thomas y EICK, Stephen G. Visualizing Program Slices. Proceedings of the
1994 IEEE Symposium on Visual Languages. pp. 288-295. Octubre 1994.
BE96 BALL, Thomas y EICK, Stephen G. Software Visualization in the Large. IEEE
Computer, pp. 33-43. Abril 1996.
BM92 BALLANCE, Robert A. y MACCABE, Arthur B. Program dependence graph for the rest
of us. Tehnical Report 92-10, University of New Mexico, Agosto 1992.
Ern94 ERNST, Michael D. Practical fine-grained static slicing of optimised code. Microsoft
Research Technical Report MSR-TR-94-14, Redmond, Julio 1994.
HDJ+95 HARMAN, Mark, DANICIC, Sebastian, JONES, Barry y otros. Project project: Tools for
program analysis and comprehension. En 4th Software Quality Conference, pages
133-157, University of Abertay-Dundee, Dundee, Julio 1995.
HLL94 HORGAN, Joseph R., LONDON, Saul y LYU, Michael R. Achieving Software Quality
with Testing Coverage Measures. IEEE Computer, pp. 60-69. Vol. 27 No. 9,
Septiembre 1994.
Hof95 HOFFNER, Tommy. Evaluation and comparison of program slicing tools. Technical
Report LiTH-IDA-R-95-01, Department of Computer and Information Science,
Linköping University, Sweden, 1995.
Draft – www.ucse.edu.ar/fma/~svcavadini/ 16
Draft – www.ucse.edu.ar/fma/~svcavadini/
Jar98 JARZABEK, Stan. Design of Flexible Static Program Analizers with PQL. IEEE
Transactions on Software Engineering, Vol. 24, No. 3: páginas 197-215, Marzo
1998.
Joh75 JOHNSON, Stephen C. Yacc: Yet Another Compiler-Compiler. Computing Science
Technical Report Nº 32. Bell Laboratories. Murray Hill, New Jersey, 1975.
LA94 LIVADAS, Panos E. y ALDEN, Scott D. A Toolset for Program Understanding.
Technical report, Computer and Information Sciences Department, University of
Florida, Gainesville, 1994.
LC94 LIVADAS, Panos E. y CROLL, Stephen.
System Dependence Graphs Based Parse Trees and their Use in Software
maintenance. Technical report, Computer and Information Sciences Department,
University of Florida, Gainesville, FL 32611, 1994.
LJ95 LIVADAS, Panos E. y JOHNSON, Theodore.
An Optimal Algorithm for the Construction of the System Dependence Graph.
Technical report, Computer and Information Sciences Department, University of
Florida, Gainesville, FL, 1995.
LR94 LIVADAS, PanosE. y ROSENSTEIN, Adam.
Slicing in the Presence of Pointer Variables. Technical report, Computer and
Information Sciences Department, University of Florida, Gainesville, FL 32611,
1994.
LS75 LESK, M. E., SCHMIDT, E. Lex: A Lexical Analyzer Generator. Computing Science
Technical Report Nº 39, Bell Laboratories. Murray Hill, New Jersey, 1975.
LWG+95 LYLE, James R., W ALLACE, Dolores R., GRAHAM, James R., GALLAGHER, Keith
Brian, POOLE, Joseph P. y BINKLEY, David W. Unravel: A case tool to assist
evaluation of high integrity software. Technical Report 5691, National Institute of
Standards and Technology, Gaithersburg, MD 20899, Agosto 1995.
Lyl84 LYLE, James R. Evaluating Variations on Program Slices for Debugging. PhD
thesis, Universidad de Maryland, Diciembre de 1984.
OO84 OTTENSTEIN, Karl J. y OTTENSTEIN, Linda M. The program dependence graph in a
In
Proceedings
of
the
ACM
software
development
environment.
SIGSOFT/SIGPLAN Software Engineering Symposium on Practical Software
Development Environments, volume 19(5) of ACM SIGPLAN Notices, páginas 177184, 1984.
Rep93 REPS,Thomas W. The Wisconsin Program-Integration System Reference Manual:
Release 2.0. Computer Sciences Department, University of Wisconsin-Madison,
Julio 1993.
Ste98a STEINDL, Christoph. Program Slicing (1) - Data Structures and Computation of
Control Flow Information. Technical Report 11, Institut für Praktische Informatik,
Johannes Kepler Universität Linz, Austria, Marzo 1998.
Ste98b STEINDL, Christoph. Program Slicing (2) - Computation of Data Flow Information.
Technical Report 12, Institut für Praktische Informatik, Johannes Kepler Universität
Linz, Austria, Marzo 1998.
Ven91 VENKATESH, G. A. The semantic approach to program slicing. In Proceedings of the
ACM SIGPLAN '91 Conference on Programming Language Design and
Implementation, volume 26(6), páginas 107-119, Junio 1991.
Draft – www.ucse.edu.ar/fma/~svcavadini/ 17
Draft – www.ucse.edu.ar/fma/~svcavadini/
WEC+94 W EISE, Daniel, ERNST, Michael, CREW , Roger F. y STEENSGAARD, Bjarne. Value
Dependence Graphs: Representation Without Taxaction. Microsoft Research
Technical Report MSR-TR-94-03, Redmond, Abril 1994.
Wei84 W EISER, Mark. Program slicing. IEEE Transactions on Software Engineering,
10(4):352-357, Julio 1984.
Draft – www.ucse.edu.ar/fma/~svcavadini/ 18

Documentos relacionados