Restringir algunas estructuras C para residir en regiones específicas del montón.
Al usar C para implementar un tiempo de ejecución para un lenguaje de programación, es posible que deseemos distinguir las estructuras de datos de tiempo de ejecución internas (asignadas usando malloc / free o algún tipo de grupo de memoria o tal vez mmap de una imagen volcada) de los objetos de usuario asignados en un montón administrado GC.
En mono, el tiempo de ejecución representa objetos administrados que se derivan de System.Object utilizando una estructura C typedef struct _MonoObject { ... } MonoObject . Mono utiliza la convención de que una clase de clase T si su primer miembro es de tipo T:
struct _MonoString {
MonoObject obj ; /* System.String derives from System.Object */
...
}; Mono está haciendo la transición a un régimen donde los punteros para la memoria administrada MonoObject *ptr deben acceder a las partes internas de tiempo de ejecución indirectamente a través de los manijas 1 : MonoObjectHandle h
Este paquete proporciona una biblioteca que analiza los archivos C para encontrar lugares donde se utilizan punteros sin procesar para la memoria administrada.
Así es como se podría usar Centrinel y Centrinel Informe Revise un proyecto AutoTools usando Bear para interceptar las invocaciones del compilador C:
# assuming you have GHC and cabal installed
$ pushd $CENTRINEL_DIR # go to the centrinel source directory
$ echo "Building Centrinel"
$ cabal sandbox init
$ cabal install happy
$ cabal install alex
$ cabal install --dependencies-only
$ cabal configure
$ cabal build
$ popd
$ echo Building project using "bear"
$ pushd $SRC_DIR
$ ./autoconf ...
$ bear make
# produces a compile_commands.json file
$ popd
$ cd $CENTRINEL_DIR
$ curl -o centrinel-report.tar.gz https://github.com/lambdageek/centrinel-report/releases/download/v0.3.1/centrinel-report.tar.gz
$ tar xvzf centrinel-report.tar.gz
# writes a skeleton HTML report to centrinel-report/
$ cabal run centrinel -- --project $SRC_DIR/compile_commands.json --exclude $SRC_DIR/thirdparty --format json --output centrinel-report/centrinel-report.json
# produces centrinel-report/centrinel-report.json
$ cd centrinel-report && python -m SimpleHTTPServer 8000
# go look at http://localhost:8000/
Este es un prototipo de desarrollo temprano, por lo que la configuración está un poco involucrada.
Necesitará un GHC reciente (probado con GHC 8.2.x, GHC 8.0.x y 7.10.x) y Cabal.
Dependencias: este programa utiliza la biblioteca language-c para el análisis C: necesitará el alex Lexer y el analizador happy instalado (ya sea en todo el sistema o en el sandbox para este repositorio). Los pasos a continuación configuran un sandbox e instalan los programas necesarios en él. (No necesitas alex y happy de ejecutar el análisis, solo para construir el analizador binario).
git clone https://github.com/lambdageek/centrinel.git
cd centrinel
cabal sandbox init
cabal install happy
cabal install alex
cabal install --dependencies-only
cabal configure
cabal build
cabal run centrinel -- --helpinclude/centrinel.h Centrinel se basa en algunos atributos __attribute__((...)) y algún preprocesador define para decirle qué analizar. Como conveniencia, cuando Centrinel invoca el preprocesador C, incluye automáticamente el archivo include/centrinel.h antes del código de usuario. Si se ejecuta desde una caja de arena, como se indicó anteriormente, el comando cabal run centrinel asegurará que Centrinel pueda encontrar este archivo. Si, en su lugar, usa cabal install , el encabezado Centrinel se copiará en el directorio de datos de Cabal, y el binario centrinel que se construye se referirá a esa ubicación incluso si posteriormente mueve el binario.
Este encabezado define __CENTRINEL__ a 1 para indicar que Centrinel está funcionando; __CENTRINEL_MANAGED_ATTR atributo y __CENTRINEL_MANAGED_REGION Atributo Especificador que puede usar para anotar sus estructuras, así como macros para definir ciertas primitivas de CCG que no se entienden por language-c .
Centrinel incluye automáticamente el encabezado, no tiene que incluirlo explícitamente.
Ahora debería poder jugar con él usando cabal run centrinel -- [ARGS] (o cabal repl si desea ejecutar los diversos pasos por separado). Además, hay un script centrinelcc que se puede usar como CC en invocaciones make como reemplazo de gcc o clang .
Uso: centrinel [--output FILE] -- CFLAGS CFILE
El programa comprende un mínimo de opciones de línea de comandos cc , como -D y -I y -U , y pasará a otros al preprocesador. Algunas opciones que no tienen sentido para el preprocesamiento (como -c o -MT se entienden y se dejan caer en silencio). Por defecto, los resultados de análisis se imprimen a STDOUT; Para dirigirlos a un archivo, agregue una opción --output FILE .
$ cabal run centrinel -- c-examples/attrib.c
Errors:
c-examples/attrib.c:28: (column 2) [WARNING] >>> Region mismatch: Region 1 and Region 2
Additional locations:
c-examples/attrib.c:8: (column 2)
c-examples/attrib.c:13: (column 1)
c-examples/attrib.c:27: (column 1)
c-examples/attrib.c:35: (column 5) [ERROR] >>> Naked pointer(s) to managed object(s) found in declaration
Pointer to managed heap XP
in 0th argument 'x' at c-examples/attrib.c:35: (column 13)
in function declaration 'foo'
c-examples/attrib.c:37: (column 11) [ERROR] >>> Naked pointer(s) to managed object(s) found in declaration
Pointer to managed heap struct Y *
in return type
in function declaration 'bar'
Pointer to managed heap XP
in 1st argument 'x' at c-examples/attrib.c:37: (column 26)
in function declaration 'bar'
c-examples/attrib.c:39: (column 5) [ERROR] >>> Naked pointer(s) to managed object(s) found in declaration
Pointer to managed heap XP
in 0th argument 'x' at c-examples/attrib.c:33: (column 28)
in type defined at c-examples/attrib.c:33: (column 1)
at c-examples/attrib.c:39: (column 10)
in 0th argument 'f' at c-examples/attrib.c:39: (column 19)
in function declaration 'baz'
Nota : Si necesita pasar una opción que comience con un tablero - y está usando cabal run , debe escribir -- veces: una vez para Cabal y una vez para Centrinel: cabal run -- -- -DFOO -I../.. c-examples/attrib.c )
Uso: centrinel [--output FILE] --project compile_commands.json
Una base de datos de compilación Clang es un archivo JSON que especifica un conjunto de invocaciones de compiladores. Se pueden usar herramientas como cmake o Bear para generar la base de datos de compilación (generalmente llamada compile_commands.json ). Centrinel puede usar la base de datos con la opción --project :
$ bear make -C some_project_directory # Note: doesn't work on OSX with System Integrity Protection
$ cabal run centrinel -- --project compile_commands.json
CC en una marca El archivo scripts/centrinelcc se puede utilizar como el valor de la variable CC para make . Primero ejecutará el compilador real (especificado por la variable de entorno REAL_CC , o cc si no lo establece) y si la compilación tiene éxito, invocará centrinel (que debe estar en la ruta)
Estos pasos aún no están automatizados
$ cabal install
$ cp dist/build/centrinel/centrinel [somewhere on your PATH]
$ cp scripts/centrinelcc [somewhere on your PATH]
$ export REAL_CC=/path/to/your/cc # if unset, defaults to 'cc'
$ make CC=centrinelcc
De forma predeterminada, Centrinel utilizará el valor de la variable de entorno REAL_CC para ejecutar el preprocesador, o cc si no log. Otra forma de especificar el compilador es usar la opción --use-cc CC que tiene prioridad sobre la variable de entorno.
Experimental : con --format json Centrinel escribirá resultados de análisis como un blob JSON (cuyo formato está bastante en flujo en este momento). El blob se puede consumir con, por ejemplo, Centrinel Informe
Con --exclude DIR (que puede especificarse varias veces), no se analizará cualquier archivo de entrada que esté en DIR o uno de sus subdirectorios. (Funciona tanto con -- CFLAGS CFILE como con --project JSON_FILE ).
Las anotaciones de la región en las definiciones de estructura (especificadas por __attribute__((__region(N))) con entero n ) se unificarán con regiones inferidas para el primer miembro de la estructura (siempre que sea otro tipo de estructura) y se informarán conflictos.
Los punteros a las estructuras en la región __CENTRINEL_MANAGED_REGION (definida como __region(1) en include/centrinel.h ) provocarán un error si ocurren en cualquier lugar de un prototipo de función (ya sea una declaración o una definición).
Comprobación de cuerpos de función para el uso de __CENTRINEL_MANAGED_REGION Pointers.
Una forma de anotar funciones/estructuras benditas que se les permite manipular punteros al montón administrado sin un error usando __CENTRINEL_SUPPRESS_ATTR(1) que se puede aplicar a:
{
l: __CENTRINEL_SUPPRESS_ATTR ( 1 ) ;
/* your code that manipulated managed objecs */
} int __CENTRINEL_SUPPRESS_ATTR ( 1 ) foo (...); /* no warnings about pointers in ... */__CENTRINEL_SUPPRESS_ATTR(0) se puede usar para volver a verificar dentro de un contexto suprimido. Esto es útil para, por ejemplo, la expansión de la macro: desea que se confíe en el cuerpo de la macro, por lo que se suprime la verificación del puntero, pero los argumentos no son compensados para que se verifiquen.1 : Un beneficio inmediato es que si se produce una recolección de basura mientras se ejecuta el código de tiempo de ejecución nativo, no tenemos que fijar el objeto referenciado, lo que puede reducir la fragmentación. ↩