• Aucun résultat trouvé

4.4 Programmes autonomes

4.4.3 D´eclarations affects et raises

L’ex´ecution d’un programme consiste `a ´evaluer successivement chacune de ses unit´es, dans l’ordre sp´ecifi´e `a la compilation. Une fois chacune de ses unit´es compil´ees, le programme exemple est assembl´e par la commande suivante :

ocamlc -o passwd2shadow passwd.cmo shadow.cmo verbose.cmo main.cmo

84 Chapitre 4·D´efinitions de types et de modules

L’ex´ecution du binairepasswd2shadow´evalue le corps des unit´esPasswd, Shadow, Verbosepuis Main, jusqu’`a ce qu’une exception non rattrap´ee soit rencontr´ee ou la fin du programme atteinte.

Ainsi, lorsqu’elle prend le contrˆole, chaque unit´e re¸coit l’information que les pr´ec´edentes ont termin´e normalement. Pour prendre en compte ces possibles flots d’information, il faut comparer les bornes des structures sous-jacentes, comme si le programme ´etait d´efini dans une seule unit´e comme

Passwd = ...

Shadow = ...

Verbose = ...

Main = ...

Dans ce but, chaque fichier interface doit mentionner, si elles ne sont pas vides, les bornes inf´erieures et sup´erieures de la structure d´efinie dans le fichier impl´ementation correspondant, grˆace aux d´eclarations et qui doivent apparaˆıtre dans son en-tˆete. Lorsque l’impl´ementation est typ´ee, les bornes sont inf´er´ees et compar´ees `a celles donn´ees dans l’interface. Par exemple, l’interface de l’unit´eVerbosed´eclare les bornes suivantes :

!arg

!arg

qui signifient que l’unit´eVerbosea des effets de bord de niveau!arget peut lever des exceptions de ce mˆeme niveau.

Lors de l’assemblage d’une s´erie d’unit´e de compilationsUnit1,. . .,Unitn, il faut v´erifier que, pour chaque unit´eUniti+1, les bornes sup´erieures deUnit1,. . .,Unitisont inf´erieures ou ´egales `a la borne inf´erieure deUniti+1. Cela est effectu´e par la commandeflowcamlpol, en mˆeme temps qu’elle calcule la politique de s´ecurit´e :

flowcamlpol passwd.fcmi shadow.fcmi debug.fcmi main.fcmi

C’est la raison pour laquelle les unit´es de compilation doivent lui ˆetre donn´ees dans le mˆeme ordre que pour l’assemblage du programme.

4.4·Programmes autonomes 85

Un exemple complet

passwd.fmli

!passwd_file < !password

(* An entry of "/etc/passwd" is represented by a record of type [(!passwd_file, !password) entry] *)

(’a, ’b) entry = { login: ’a string;

password: ’b string }

(* Input from "/etc/passwd" *)

(#’a: ) in_channel

open_in: unit -{!passwd_file ||}-> !passwd_file in_channel

input_entry: [< !passwd_file] in_channel -{!passwd_file | End_of_file: !passwd_file |}->

(!passwd_file, !password) entry

close_in: [< !passwd_file] in_channel -{!passwd_file ||}-> unit

passwd.ml

entry =

{ login: string;

password: string }

in_channel = Pervasives.in_channel

open_in () =

Pervasives.open_in "/etc/passwd"

input_entry chan =

line = input_line chan

i1 = String.index line ’:’

i2 = String.index_from line (i1 + 1) ’:’

{ login = String.sub line 0 i1;

password = String.sub line (i1 + 1) (i2 - i1 - 1) }

Not_found -> input_entry chan

close_in chan =

Pervasives.close_in chan

shadow.fmli

!shadow_file < !shadow_password

(* An entry of "/etc/shadow" is represented by a record of type [(!shadow_file, !shadow_password) entry] *)

(’a, ’b) entry = { login: ’a string;

86 Chapitre 4·D´efinitions de types et de modules

4.4·Programmes autonomes 87

close_out chan =

Pervasives.close_out chan

verbose.fmli

!arg < !stderr

!arg < !stdout

!arg

!arg

message : !stdout string -{!stdout ||}-> unit

verbose.fml

!arg < !stderr, !stdout

(** [!verbose_mode] is true if the verbose mode is active. *)

verbose_mode : (!arg bool, _) ref = ref false

(** Parse command-line arguments. If the option "-v" if found then [verbose_mode] is set to true. If any other option is encountered then an error message is printed and the exception [Exit] is raised. *)

_ =

i = 1 Array.length Sys.argv - 1

Sys.argv.(i)

"-v" -> verbose_mode := true

| option ->

prerr_string "Invalid option ";

prerr_endline option;

Exit

(** [print message] print a message on the standard output if the verbose mode is enabled. Otherwise, it does nothing. *)

message s =

!verbose_mode print_endline s

main.fml

!passwd_file < !shadow_file

!passwd_file, !shadow_file < !stdout

!passwd_file, !shadow_file < !shadow_password

!password < !shadow_password

(** The module [StringMap] implements association tables indexed by strings. *)

StringMap = Map.Make (

88 Chapitre 4·D´efinitions de types et de modules

’a t = ’a string

compare = Pervasives.compare

)

(** [read_shadow ()] reads the content of /etc/passwd and returns a map associating each login to its entry. *)

read_shadow () =

in_chan = Shadow.open_in ()

loop accu =

entry = Shadow.input_entry in_chan

loop (StringMap.add entry.Shadow.login entry accu)

End_of_file ->

Shadow.close_in in_chan;

accu

loop StringMap.empty

(** [read_passwd shadow_map] generates /etc/shadow from /etc/passwd and the entries in [shadow_map] *)

read_passwd shadow_map =

in_chan = Passwd.open_in ()

out_chan = Shadow.open_out ()

loop () =

passwd_entry = Passwd.input_entry in_chan Verbose.message passwd_entry.Passwd.login;

shadow_entry =

StringMap.find passwd_entry.Passwd.login shadow_map

Not_found ->

Verbose.message " creating an entry";

{ Shadow.login = passwd_entry.Passwd.login;

Shadow.password = passwd_entry.Passwd.password;

Shadow.rem = ""

}

Shadow.output_entry out_chan shadow_entry

End_of_file -> ()

4.4·Programmes autonomes 89

loop ();

Passwd.close_in in_chan;

Shadow.close_out out_chan

_ =

shadow_map = read_shadow () read_passwd shadow_map

II

D E U X I `E M E P A R T I E

Une analyse typ´ ee de flots

d’information pour ML

93

C

ette deuxi`eme partie formalise l’analyse typ´ee de flots d’information mise en œuvre dans le syst`eme Flow Caml, pour un noyau du langage ML, que je d´enomme Core ML. Il s’agit d’un λ-calcul en appel par valeur muni de polymorphisme « let », d’exceptions et de constantes. J’ai cherch´e `a donner une pr´esentation du langage et du syst`eme de types aussi modulaire que possible en laissant ouverte la d´efinition de ses constructeurs et destructeurs. Je montre toutefois comment le langage peut ˆetre muni — par un choix appropri´e de ces constantes — de fonctionnalit´es usuelles : arithm´etique, r´ef´erences, structures de donn´ees.

Les syst`emes de types sont g´en´eralement utilis´es pour garantir la pr´eservation d’un certain invariant lors de l’´evaluation d’une expression, permettant ainsi d’´etablir statiquement des pro-pri´et´es dynamiques des programmes. L’absence d’erreur `a l’ex´ecution est certainement l’exemple le plus habituel de telle propri´et´e. Le syst`eme que je pr´esente ici ´etablit quant `a lui un r´esultat de non-interf´erence[GM82]. Cependant, l’´enonc´e et la preuve d’une telle propri´et´e n´ecessitent de consid´erer deux ex´ecutions a priori ind´ependantes d’un mˆeme programme, initialis´ees avec des valeurs d’entr´ees diff´erentes, pour montrer qu’elle produisent le mˆeme r´esultat. C’est pourquoi, son traitement est g´en´eralement plus d´elicat et des approches vari´ees sont propos´ees dans la litt´erature.

Abadi, Lampson et L´evy [ALL96] ont donn´e une s´emantique op´erationnelle ´etiquet´ee du λ-calcul, o`u la quotit´e d’information port´ee par les expressions est indiqu´ee par des ´etiquettes qui leur sont attach´ees. L’ex´ecution d’un programme dans une telle s´emantique permet d’effectuer une analyse de flots d’information dynamique. Pottier et Conchon [PC00] ont ensuite montr´e comment une analyse statique typ´ee pouvait ˆetre d´eriv´ee et prouv´ee correcte `a partir de cette s´emantique.

Toutefois, dans une langage autorisant, comme Core ML, l’´evaluation des expressions `a produire des effets de bords, un flot d’information peut avoir pour origine l’absence d’un certain effet.

Consid´erons par exemple le fragment de code suivant : ifx= 1theny:= 1

94

Si, apr`es l’´evaluation de cette expression, la r´ef´erenceyne contient pas l’entier1alorsxne peut ˆetre l’entier1lui-mˆeme. Dans ce cas, l’ex´ecution transf`ere de l’information dexvers la r´ef´erencey bien que le contenu de cette derni`ere ne soit pas modifi´e. Il semble difficile d’´etendre une s´emantique

´etiquet´ee, telle que celle d’Abadi, Lampson et L´evy, pour capturer ce type de ph´enom`ene. Cela m’am`ene `a envisager une autre approche.

Les preuves de non-interf´erencedirectes, bien que relativement ais´ees dans le cas de langages de programmation simples [VSI96], deviennent de plus en plus complexes en pr´esence de traits avanc´es dans le langage ´etudi´e — tels que l’allocation m´emoire, les m´ecanismes d’exceptions ou les clˆotures

— ou bien dans le syst`eme de type utilis´e — tels que le polymorphisme. En effet, elles peuvent ˆetre vue comme des preuves de bisimulationet n´ecessitent ainsi la consid´eration d’invariants complexes, comme par exemples ceux manipul´es par Zdancewic et Myers [ZM01a, ZM02].

Pour contourner ces difficult´es, j’ai d´ecompos´e mon approche en plusieurs ´etapes ind´ependantes.

Tout d’abord, dans le chapitre 5(page 97), je d´efinis une extension ad hoc particuli`ere de Core ML, d´enomm´ee Core ML2, qui permet de raisonner explicitement sur les points communs et les diff´erences entre deux configurations d’un programme. Je prouve que cette extension est correcte dans un certain sens en donnant un ´enonc´e de simulation(th´eor`eme 5.13, page 110). Ensuite, le chapitre6(page113) pr´esente un syst`eme de type pour ce langage ´etendu (et par l`a mˆeme pour Core ML qui en est un sous-ensemble). Je montre alors une propri´et´e standard de stabilit´e du typage par r´eduction (th´eor`eme6.17, page128). La propri´et´e de non-interf´erence pour le langage de base (th´eor`eme6.21, page134) est obtenue alors de mani`ere ´el´ementaire en combinant les deux r´esultats pr´ec´edents. En d’autres termes, j’ai r´eduit le probl`eme initial de non-interf´erencepour Core ML en une propri´et´e de pr´eservation du typage pour Core ML2, grˆace `a l’expression de l’invariant de bisimulation dans le syst`eme de types lui-mˆeme.

Dans la tradition de ML, le syst`eme de type est ´equip´e de polymorphisme « let » et d’un algorithme de synth`ese des types. Ces deux caract´eristiques se r´ev`elent fondamentales pour son utilisation pratique : outre la forme des valeurs produites, les types associ´es aux expressions d´e-crivent les effets produits par leur ex´ecution et la quotit´e d’information attach´ee au r´esultat. Ainsi, le polymorphisme permet d’´ecrire du code g´en´erique vis-`a-vis de chacune de ces trois composantes,

´evitant par exemple la duplication d’une fonction devant ˆetre utilis´ee avec des donn´ees de niveaux diff´erents. L’inf´erence de types permet au programmeur de v´erifier son code sans l’annoter, ce qui ne serait pas r´ealiste ´etant donn´e la verbosit´e et la complexit´e des types. Le syst`eme est ´egale-ment ´equip´e de sous-typage, ce qui permet d’obtenir une description pr´ecise car orient´eedes flots d’information. Il est par cons´equent `a base de contraintes. Cependant, si j’´etablissais le r´esultat de non-interf´erence directement sur ce syst`eme, il me faudrait prendre en compte les m´ecanismes syntaxiques de g´en´eralisation et d’instanciation, ainsi que la gestion des contraintes, au sein mˆeme de la preuve relative `a la correction de l’analyse. Cette derni`ere serait tr`es certainement compliqu´ee et les points nouveaux relatifs `a l’analyse de flots obscurcis par des probl`emes techniques, comme la gestion des noms, mais bien connus. Pour contourner cette derni`ere difficult´e, j’ai adopt´e l’approche

95

semi-syntaxiquede Pottier [Pot01a], qui consiste en deux ´etapes. Tout d’abord, dans le chapitre 6 (page113), j’´etudie un syst`eme de types ´equip´e d’une forme extensionelle de polymorphisme, dont le traitement est tr`es simple puisqu’il ne fait intervenir que des types bruts, c’est-`a-dire des types sans variables. Ensuite, dans le chapitre7(page 135), je construis un syst`eme `a base de contrain-tes, dans le style de HM(X) [OSW99], pourvu d’un algorithme d’inf´erence. Je prouve la correction de ce syst`eme en traduisant ses jugements dans le pr´ec´edent.

Les r´esultats pr´esent´es dans cette partie ont ´et´e co-publi´es avec Fran¸cois Pottier, en anglais, dans les actes de la conf´erence ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL 2002)[PS02] puis dans le journalACM Transactions on Programming Languages and Systems (TOPLAS)[PS03].