• Aucun résultat trouvé

Gestion des erreurs et exceptions

_ _(AbortCode opstack_error state) end

end end end ) end end end end.

3.5 Gestion des erreurs et exceptions

Lors de l’ex´ecution d’un programme, le d´eroulement normal des calculs peut ˆetre interrompu par un programme `a la forme incorrecte ou une condi-tion non r´ealis´ee d’un calcul. Dans le premier cas, il s’agit d’une erreur du programme (comme l’appel `a l’instructionpop avec une pile vide, un typage incorrect, ...) qui conduit `a la terminaison abrupte de l’ex´ecution. Dans le second cas, le m´ecanisme des exceptions, pr´esent dans beaucoup de langages de programmation r´ecents et qui se traduit par un changement dans le flot de contrˆole normal du programme, permet un gestion efficace de ces erreurs dynamiques d’ex´ecution.

3.5.1 Les erreurs

A nouveau, l’origine des erreurs dans la machine virtuelle peut provenir` de diff´erentes sources. Il peut s’agir :

– d’une erreur du code (branchement `a une adresse incorrecte, pile vide, ...) ;

– d’une incoh´erence du programme (classe inexistante, champ man-quant, ...) ;

– d’une incoh´erence de la m´emoire (objet non trouv´e ou pas du type attendu).

Le signalement de ces erreurs dans la machine virtuelle s’effectue respecti-vement avec l’utilisation des fonctionsAbortCode,AbortCapetAbortMemory. Ces fonctions construisent un ´etat anormal (Abnormal) `a partir de la raison et de l’´etat donn´es en argument. La raison, du type inductifeReason

suivant, n’est pr´esente que pour aider `a rendre plus claire la cause de l’erreur :

Inductive eReason : Set :=

heap_error : eReason | sheap_error : eReason | opstack_error : eReason | checkcast_error : eReason | store_error : eReason | overflow_error : eReason | init_error : eReason | [...]

L’ex´ecution ne peut continuer `a partir d’un ´etat anormal et la machine virtuelle termine.

3.5.2 Les exceptions

EnJava, lors du lancement d’une exception, un objetJava est cr´e´e dont le type donne la raison de l’erreur. Un m´ecanisme de rattrapage de l’excep-tion intervient alors et recherche parmi la pile des contextes d’ex´ecution de m´ethode la m´ethode contenant le code `a ex´ecuter lorsqu’une telle exception est lanc´ee. Le flot de contrˆole est alors transmis au d´ebut de ce code et l’ex´ecution continue.

Le lancement d’exceptions peut ˆetre r´ealis´e ou bien directement par la machine virtuelle (dans le cas d’une division par z´ero par exemple) ou par le programmeur (utilisation du mot-cl´eJavathrowdans le code source, traduit vers le code octetathrow).

Lorsque la machine virtuelle lance d’elle-mˆeme une exception, l’´etat de retour de l’instruction ex´ecut´ee a pour constructeur ThrowException et

comme arguments l’´etat courant et un terme du typexLabelindiquant l’ex-ception `a lancer :

Inductive xLabel : Set :=

Arithmetic : xLabel |

ArrayStore : xLabel |

ClassCast : xLabel |

IndexOutOfBounds : xLabel | ArrayIndexOutOfBounds : xLabel | NegativeArraySize : xLabel | NullPointer : xLabel |

Security : xLabel .

Un objet java du type correspondant `a l’exception voulue est alors cr´e´e dans le tas et la fonction CatchException (dont le comportement est d´ecrit `a la section 3.5.3, qui suit) est appel´ee.

Dans le cas du code octet athrow, l’objet repr´esentant l’exception `a lancer a d´ej`a ´et´e cr´e´e par des codes octet pr´ec´edant l’instruction et la fonc-tionCatchException est, apr`es quelques v´erifications sur cet objet, appel´ee

´egalement.

3.5.3 Récupération d’exceptions

La r´ecup´eration des exceptions est principalement un probl`eme de re-cherche dans la pile des contextes d’ex´ecution.

Chaque m´ethode poss`ede sa liste de gestionnaires d’exceptions, il s’agit du champ handler_list de l’enregistrement Method (cf section 3.2.2). Un gestionnaire d’exception est d´ecrit par le typehandler_type:

Definition handler_type :=

(bytecode_idx*bytecode_idx*cap_class_idx*bytecode_idx).

o`u les deux premiers index de code octet indiquent la port´ee du code dans la m´ethode (un bloc) o`u doit se trouver le pointeur d’ex´ecution pour qu’une exception de type compatible avec la classe donn´ee en troisi`eme composante puisse ˆetre g´er´ee. La derni`ere composante indique l’emplacement du code (`a l’int´erieur du code de la m´ethode) o`u brancher dans le cas o`u l’exception est r´ecup´er´ee par ce gestionnaire.

Une m´ethode est alors en mesure de rattraper une exception si elle pos-s`ede un gestionnaire d’exception tel que :

– sa port´ee inclut le pointeur d’ex´ecution ;

– l’exception lev´ee est une instance ou une instance d’une sous-classe de la classe g´er´ee.

Lors du lancement d’une exception, le m´ecanisme de r´ecup´eration d’ex-ception commence par observer si la m´ethode courante (celle du haut de la pile de contextes d’ex´ecution) peut g´erer l’exception. Le cas ´ech´eant, l’ex´ e-cution reprend `a l’emplacement indiqu´e par le gestionnaire d’exception. Si-non, le contexte d’ex´ecution courant est enlev´e de la pile des contextes et l’algorithme recommence. Cela se traduit simplement par la fonction Coq suivante (une des seules de la formalisation `a ˆetre exprim´ee par un point fixe) :

Fixpoint lookup_stack [s:stack] :

Classjcprogram(option (bytecode_idx*stack)) :=

[cl:Class][cap:jcprogram]

Cases s of

(∗ s t a c k empty : e x c e p t i o n uncaught ∗) nil (None ?) |

(cons h lf)

(∗ l o o k u p i n c u r r e n t frame ∗) Cases (lookup_frame cl h cap) of

(∗ h a n d l e r found i n h : r e t u r n b r a n c h i n g p o i n t and c u r r e n t s t a c k ∗) (Some u) (Some ? (u,s)) |

(∗ no h a n d l e r found i n frame h : c o n t i n u e l o o k u p i n l f ∗) None (lookup_stack lf cl cap)

end end.

On remarque qu’il s’agit d’une fonction partielle et que l’on peut se trouver dans une situation o`u aucun contexte ne g`ere l’exception. L’ex´ecution du programme s’arrˆete alors.

On notera ´egalement qu’`a l’int´erieur d’un mˆeme contexte d’ex´ecution, plusieurs gestionnaires peuvent g´erer une exception. Le gestionnaire choisi est alors celui dont la port´ee du bloc gestionnaire est la moins large.