Restrinja algumas estruturas C para residir em regiões específicas da pilha.
Ao usar o C para implementar um tempo de execução para uma linguagem de programação, podemos querer distinguir estruturas de dados de tempo de execução internas (alocadas usando malloc / free ou algum tipo de pool de memória ou talvez mmap de uma imagem despejada) de objetos de usuário alocados em um heap gerenciado GC.
No mono, o tempo de execução representa objetos gerenciados que derivam do System.Object usando um c struct typedef struct _MonoObject { ... } MonoObject . Mono usa a Convenção de que uma classe Divies da Classe T se seu primeiro membro for do Tipo T:
struct _MonoString {
MonoObject obj ; /* System.String derives from System.Object */
...
}; O Mono está em transição para um regime onde os ponteiros para a memória gerenciada MonoObject *ptr devem ser acessados pelos internos de execução indiretamente via Handles 1 : MonoObjectHandle h
Este pacote fornece uma biblioteca que analisa os arquivos C para encontrar lugares onde são usados ponteiros crus na memória gerenciada.
Aqui está como se pode usar o Centrinel e o Centrinel-Report, verifique um projeto de AutoTools usando o Bear para interceptar as invocações do 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 é um protótipo de desenvolvimento inicial, portanto a configuração está um pouco envolvida.
Você precisará de um GHC recente (testado com GHC 8.2.x, GHC 8.0.x e 7.10.x) e Cabal.
Dependências: Este programa usa a biblioteca language-c para análise C - você precisará do alex Lexer e happy Parser instalado (em todo o sistema ou na caixa de areia para este repositório). As etapas abaixo configuram uma caixa de areia e instalam os programas necessários nela. (Você não precisa de alex e happy em executar a análise, apenas para construir o binário do analisador.)
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 O Centrinel conta com alguns atributos __attribute__((...)) e algum pré -processador define para dizer o que analisar. Como conveniência, quando o Centrinel invoca o pré -processador C, ele inclui automaticamente o arquivo include/centrinel.h antes do código do usuário. Se estiver fugir de uma caixa de areia, como acima, o comando cabal run centrinel garantirá que o Centrinel possa encontrar esse arquivo. Se você usar cabal install , o cabeçalho do Centrinel será copiado para o diretório de dados da CABAL e o binário centrinel que é construído se referirá a esse local, mesmo que você mova o binário posteriormente.
Este cabeçalho define __CENTRINEL__ a 1 para indicar que o Centrinel está em execução; __CENTRINEL_MANAGED_ATTR atributo e __CENTRINEL_MANAGED_REGION Specificador de atributo que você pode usar para anotar suas estruturas, bem como macros para definir certos primitivos do GCC que não são entendidos pelo language-c .
O cabeçalho é automaticamente incluído pelo Centrinel, você não precisa incluí -lo explicitamente.
Agora você deve poder brincar com ele usando cabal run centrinel -- [ARGS] (ou cabal repl se você quiser executar as várias etapas separadamente). Além disso, existe um script centrinelcc que pode ser usado como CC em make invocações como substituição para gcc ou clang .
Uso: centrinel [--output FILE] -- CFLAGS CFILE
O programa entende um modicum de opções de linha de comando cc , como -D e -I e -U , e passará por outros para o pré -processador. Algumas opções que não fazem sentido para o pré -processamento (como -c ou -MT são entendidas e silenciosamente descartadas). Por padrão, os resultados da análise são impressos para o stdout; Para direcioná -los para um arquivo, adicione uma opção --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 : Se você precisar passar uma opção que começa com um traço - você está usando cabal run , deve escrever -- vezes: uma vez para cabala e uma vez para o Centrinel: cabal run -- -- -DFOO -I../.. c-examples/attrib.c )
Uso: centrinel [--output FILE] --project compile_commands.json
Um banco de dados de compilação CLANG é um arquivo JSON que especifica um conjunto de invocações do compilador. Ferramentas como cmake ou urso podem ser usadas para gerar o banco de dados de compilação (geralmente chamado de compile_commands.json ). Centrinel pode usar o banco de dados com a opção --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 em uma marca Os scripts/centrinelcc podem ser usados como o valor da variável CC para make . Primeiro, ele executará o compilador real (especificado pela variável de ambiente REAL_CC , ou cc se não for definido) e, se a compilação for bem -sucedida, invocará centrinel (que deve estar no caminho)
Essas etapas ainda não foram automatizadas
$ 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
Por padrão, o CentRinel usará o valor da variável de ambiente REAL_CC para executar o pré -processador, ou cc se não for definido. Outra maneira de especificar o compilador é usar a opção --use-cc CC , que tem precedência sobre a variável de ambiente.
Experimental : Com --format json Centrinel, escreverá os resultados da análise como uma blob JSON (cujo formato está bastante em fluxo no momento). O bolhas pode ser consumido com, por exemplo
Com --exclude DIR (que pode ser especificado várias vezes), quaisquer arquivos de entrada que estejam no DIR ou um de seus subdiretos não serão analisados. (Funciona com o modo -- CFLAGS CFILE e com --project JSON_FILE ).
As anotações da região nas definições de estrutura (especificadas por __attribute__((__region(N))) com número inteiro n ) serão unificadas com regiões inferidas para o primeiro membro da estrutura (desde que seja outro tipo de estrutura) e os conflitos serão relatados.
Os ponteiros para estruturas na região __CENTRINEL_MANAGED_REGION (definidos como __region(1) em include/centrinel.h ) provocarão um erro se ocorrerem em qualquer lugar de um protótipo de função (uma declaração ou uma definição).
Verificação de corpos de função para uso de ponteiros __CENTRINEL_MANAGED_REGION .
Uma maneira de anotar funções/estruturas abençoadas que podem manipular ponteiros para a pilha gerenciada sem um erro usando __CENTRINEL_SUPPRESS_ATTR(1) que pode ser aplicado 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) pode ser usado para entregar a verificação de volta dentro de um contexto suprimido. Isso é útil para, por exemplo, expansão de macro: você deseja que o corpo da macro seja confiável, para que a verificação do ponteiro seja suprimida, mas os argumentos não são suprimidos para que sejam verificados.1 : Um benefício imediato é que, se uma coleta de lixo ocorrer enquanto o código de tempo de execução nativo estiver em execução, não precisamos fixar o objeto referenciado, o que pode reduzir a fragmentação. ↩