# Analyseur statique Le projet reprend et complète la base de code fournie. Nous avons implémenté l'analyse disjonctive par chemin ainsi que le domaine de Karr. Les tests de l'analyseur sont fournis avec les tests préexistants et selon leurs conventions. Ils sont intégrés à `scripts/test.sh`. Figurent des tests quand aux support des fonctions, des congruences, de l'analyse disjonctive. ## Considérations sur les domaines ### Des domaines nus Que ce soit dans les opérations en avant ou en arrière, le comportement de "Bot" (et dans une moindre mesure de "Top") dans un `VALUE_DOMAIN` ne dépend pas du domaine implémenté. Afin d'aiser l'implémentation des divers `VALUE_DOMAIN` (constantes,intervalles, congruences,signes) on a fait le choix d'implémenter un type de domaine `NAKED_VALUE_DOMAIN`, dont la sémantique est celle d'un `VALUE_DOMAIN` à ceci près que l'on interdit "Bot" et "Top" en entrée des fonctions (ce qui amène à changer un peu la signature, cf. domains/naked.ml). Un foncteur est alors défini, AddTopBot, qui complète un `NAKED_VALUE_DOMAIN` en `VALUE_DOMAIN`. Un problème qui apparait est qu'un `NAKED_VALUE_DOMAIN` peut avoir besoin d'exprimer le concept de Top ou Bot, notamment dans les opérations à l'envers. Pour gérer cela, on utilise deux exceptions, `NeedTop` et `Absurd`. ### Une signature plus expressive Afin de faciliter l'écriture du domaine de Karr, la signature de `DOMAIN` change le type de init en un `int -> t`; cela permet d'indiquer au domaine le nombre de variables prévu. ## L'itérateur ### Terminaison Dans notre projet, lors de l'exécution, certains noeuds du CFG sont annotés comme des `widen_target` : l'accumulation d'état abstrait se fait sur eux par des `widen` et non des `join`. La terminaison est alors assurée dès lors que chaque boucle apparaissant dans le CFG contient au moins une `widen_target`. Pour ce faire, on procède de deux manières : - lors de la conversion de l'AST en CFG, les noeuds "en tête" de boucle (ceux suivant immédiatement la décision de refaire un tour) sont annotés comme des `widen_target`; - cela ne suffisant pas pour les boucles "implicites" formées via des `goto`, une passe de recherche de cycle par BFS est ensuite effectuée sur chaque fonction; dès qu'elle trouve un cycle, elle note la tête du cycle comme `widen_target`. Ce deuxième mécanisme n'apportant aucune garantie sur la pertinence de la cible choisie, un avertissement est émi lorsqu'il annote un noeud. ### Itérer dans des fonctions Nous avons fait le choix, lors de l'analyse d'une fonction, de remettre à zéro les états des noeuds internes à la fonction (excepté l'entrée). Cela permet à des appels différents à la même fonction de ne pas créer d'imprécision à cause de `join` fortuits. Une telle approche pourrait se généraliser aux fonctions récursives, mais il faudrait du support vis-à-vis du passage de paramètre, de valeur de retour et la terminaison semble plus subtile à garantir. ### Les iterables Initialement, l'algorithme de _worklist_ a été implémenté directement à l'aide des domaines. Toutefois, adapter une telle structure à l'analyse disjonctive aurait nécessité de changer considérablement la signature des domaines pour l'annoter des informations de branchement. Ces subtilités ont été encapsulées dans un type de domaine `ITERABLE` (iterator/iterable.ml), dont les instances sont en toute généralité des objets permettant d'effectuer l'algorithme de _worklist._ Deux fonctions des domaines vers les itérables sont alors fournis,`SimpleIterable` fournissant une analyse naïve (disponible via l'option `-fno-disjunction`) dont les résultats sont plus lisibles et `DisjunctiveIterable` fournissant une analyse disjonctive. Dans la sortie correspondant à une analyse disjonctive, chaque noeud est associé à une fonction partielle de listes de paires entier booléen vers des éléments du domaine. Une liste de paire (entier,booléen) correspond aux exécutions ayant rencontré exactement les conditionnelles indiquées par leur `node_id` et ayant pris la branche indiquée par le booléen (au dernier passage).