Restreignez certaines structures C à résider dans des régions spécifiques du tas.
Lorsque vous utilisez C pour implémenter un runtime pour un langage de programmation, nous pouvons vouloir distinguer les structures de données d'exécution internes (allouées à l'aide malloc / free ou une sorte de pool de mémoire ou peut-être mmap à partir d'une image vide) à partir d'objets utilisateur alloués dans un tas géré GC.
Dans Mono, le runtime représente des objets gérés qui dérivent de System.Object à l'aide d'un monoObject Ctrust typedef struct _MonoObject { ... } MonoObject . Mono utilise la convention selon laquelle une classe est en termes de classe T si son premier membre est de type T:
struct _MonoString {
MonoObject obj ; /* System.String derives from System.Object */
...
}; Mono passe à un régime où les pointeurs vers la mémoire gérée MonoObject *ptr doivent être accessibles par les internes d'exécution indirectement via les poignées 1 : MonoObjectHandle h
Ce package fournit une bibliothèque qui analyse les fichiers C pour trouver des endroits où des pointeurs bruts vers la mémoire gérés sont utilisés.
Voici comment on pourrait utiliser CentRinel et Centrinel-Report Vérifier un projet AutoTools en utilisant Bear pour intercepter les invocations du compilateur 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/
Il s'agit d'un prototype de développement précoce, donc la configuration est un peu impliquée.
Vous aurez besoin d'un GHC récent (testé avec GHC 8.2.x, GHC 8.0.x et 7.10.x) et Cabal.
Dépendances: ce programme utilise la bibliothèque language-c pour C analyse de C - vous aurez besoin du alex Lexer et de Parser happy Parser (soit dans le Systemwide ou dans le bac à sable pour ce référentiel). Les étapes ci-dessous configurent un bac à sable et installez les programmes nécessaires. (Vous n'avez pas besoin alex et happy d'exécuter l'analyse, juste pour construire le binaire de l'analyseur.)
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 s'appuie sur certains attributs __attribute__((...)) et un certain préprocesseur définit pour lui dire quoi analyser. En tant que commodité, lorsque CentRinel invoque le prérocesseur C, il inclut automatiquement le fichier include/centrinel.h avant le code utilisateur. Si vous exécutez un bac à sable, comme ci-dessus, la commande cabal run centrinel garantira que CentRinel est capable de trouver ce fichier. Si à la place, vous utilisez cabal install , l'en-tête Centrinel sera copié dans le répertoire des données de Cabal, et le binaire centrinel qui est construit se référera à cet emplacement même si vous déplacez ensuite le binaire.
Cet en-tête définit __CENTRINEL__ à 1 pour indiquer que Centrinel est en cours d'exécution; __CENTRINEL_MANAGED_ATTR Attribut et __CENTRINEL_MANAGED_REGION Spécificateur que vous pouvez utiliser pour annoter vos structures, ainsi que les macros pour définir certaines primitives GCC qui ne sont pas comprises par language-c .
L'en-tête est automatiquement inclus par CentRinel, vous n'avez pas à l'inclure explicitement.
Vous devriez maintenant pouvoir jouer avec lui en utilisant cabal run centrinel -- [ARGS] (ou cabal repl si vous souhaitez exécuter les différentes étapes séparément). De plus, il existe un script centrinelcc qui peut être utilisé comme CC dans make invocations en remplacement de dépôt pour gcc ou clang .
Utilisation: centrinel [--output FILE] -- CFLAGS CFILE
Le programme comprend un minimum d'options de ligne de commande cc telles que -D et -I et -U et passera les autres au préprocesseur. Quelques options qui n'ont pas de sens pour le prétraitement (telles que -c ou -MT sont comprises et abandonnées en silence). Par défaut d'analyse, les résultats sont imprimés sur STDOUT; Pour les diriger vers un fichier, ajoutez une option --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'
Remarque : Si vous avez besoin de passer une option qui commence par un tableau de bord - et que vous utilisez cabal run , vous devez écrire -- deux fois: une fois pour Cabal et une fois pour Centrinel: cabal run -- -- -DFOO -I../.. c-examples/attrib.c )
Utilisation: centrinel [--output FILE] --project compile_commands.json
Une base de données de compilation Clang est un fichier JSON qui spécifie un ensemble d'invocations du compilateur. Des outils tels que cmake ou Bear peuvent être utilisés pour générer la base de données de compilation (généralement appelée compile_commands.json ). Centrinel peut utiliser la base de données avec l'option --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 dans une marque Les scripts/centrinelcc peuvent être utilisés comme valeur de la variable CC pour make . Il exécutera d'abord le compilateur réel (spécifié par la variable d'environnement REAL_CC , ou cc si unset) et si la compilation réussit, il invoquera centrinel (qui doit être sur le chemin)
Ces étapes ne sont pas encore automatisées
$ 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
Par défaut, Centrinel utilisera la valeur de la variable d'environnement REAL_CC pour exécuter le préprocesseur, ou cc si unset. Une autre façon de spécifier le compilateur consiste à utiliser l'option --use-cc CC qui a priorité sur la variable d'environnement.
Expérimental : avec --format json Centrinel rédigera des résultats d'analyse en tant que blob JSON (dont le format est tout à fait en flux en ce moment). Le blob peut être consommé avec, par exemple le rapport centrinel
Avec --exclude DIR (qui peut être spécifié plusieurs fois), tous les fichiers d'entrée qui sont dans DIR ou l'un de ses sous-répertoires ne seront pas analysés. (Fonctionne à la fois avec -- CFLAGS CFILE MODE ET AVEC --project JSON_FILE ).
Les annotations de région sur les définitions de structure (spécifiées par __attribute__((__region(N))) avec entier n ) seront unifiées avec les régions déduites pour le premier membre de la structure (à condition qu'il s'agisse d'un autre type de structure) et des conflits seront signalés.
Les pointeurs vers des structures dans la région __CENTRINEL_MANAGED_REGION (définis comme __region(1) dans include/centrinel.h ) provoqueront une erreur si elles se produisent n'importe où dans un prototype de fonction (soit une déclaration ou une définition).
Vérification des corps de fonction pour l'utilisation des pointeurs __CENTRINEL_MANAGED_REGION .
Une façon d'annoter les fonctions / structures bénies qui sont autorisées à manipuler les pointeurs vers le tas géré sans erreur en utilisant __CENTRINEL_SUPPRESS_ATTR(1) qui peut être appliqué à:
{
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) peut être utilisé pour remettre la vérification dans un contexte supprimé. Ceci est utile pour, par exemple, l'expansion de la macro: vous voulez que le corps de la macro soit fait confiance, de sorte que la vérification du pointeur est supprimée, mais les arguments ne sont pas soutenus afin qu'ils soient vérifiés.1 : Un avantage immédiat est que si une collection d'ordures se produit pendant l'exécution du code d'exécution native, nous n'avons pas à épingler l'objet référencé, ce qui peut réduire la fragmentation. ↩