Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

CoqBlog

.NET is good :-)
{ Blog de coq }

Actualités

Debug : "Set Next Statement" ("Définir l'instruction suivante") n'est PAS une machine à remonter le temps

Je dois bien admettre que je ne suis pas très fan de cette fonctionnalité.
Sous Visual Studio elle s'appelle "Set Next Statement" ("Définir l'instruction suivante"), sous SharpDevelop c'est "Set current statement" (ou "Définir l'instruction suivante" si l'IDE est en français) et à ma connaissance cette fonctionnalité n'est pas disponible sous MonoDevelop (du moins sous Windows).

Dans tous les cas, il est important que l'utilisateur du debugger comprenne bien ce que fait cette fonctionnalité et surtout ce qu'elle ne fait pas.
A noter que dans ce post je ne parle en aucun cas de la fonctionnalité IntelliTrace apparue avec Visual Studio 2010 (édition Ultimate minimum...), sur laquelle je n'ai de toute façon aucun recul.

 

Où se trouve cette fonctionnalité ?

Lors d'une session de debug elle est utilisable, par exemple lorsqu'un point d'arrêt est atteint, depuis les menus contextuels ou par simple déplacement du curseur jaune.

Sous Visual Studio :
Capture d'écran de l'élément "Set Next Statement" du menu contextuel de Visual Studio

Sous SharpDevelop :
Capture d'écran de l'élément "Set current statement" du menu contextuel de SharpDevelop

 

Ce que cette fonctionnalité ne fait pas

La fonctionnalité Set Next Statement n'est PAS une machine à remonter le temps : si nous l'utilisons pour déplacer le point d'exécution à un endroit que nous avons déjà passé, les effets des instructions qui ont eu lieu entre ce point dans le passé et le point présent ne seront PAS annulés.
Il n'y a aucun mécanisme de rollback sur les changements d'états, les changements en mémoire en général et encore moins sur les éléments externes (bases de données, fichiers, ...)

 

Ce que cette fonctionnalité fait

Elle ne fait rien d'autre que ce qu'elle annonce : elle nous permet de changer le point d'exécution, c'est-à-dire de définir l'instruction à partir de laquelle l'exécution reprendra quand l'exécution du thread sera relancée.
Cette manoeuvre peut être effectuée, au sein d'une méthode, vers l'avant (pour éviter d'exécuter certaines instructions) ou vers l'arrière (pour recommencer l'exécution de certaines instructions).

Un cas d'utilisation courant de cette fonctionnalité est lorsque l'utilisateur du debugger effectue un step over sur un appel de méthode au lieu du step into qu'il voulait faire.
Dans ce genre de cas l'utilisateur du debugger va vouloir rejouer l'exécution de la méthode sans reprendre sa session de debug de zéro.
Cette manoeuvre est rarement sans risque : il faudrait pour cela que l'exécution de la méthode ne modifie en rien l'état du programme, et qu'elle n'utilise aucune donnée qui soit modifiée par un autre thread ou un élément externe.

 

A quoi faut-il faire attention en utilisant cette fonctionnalité ?

A tout.

Il faut faire attention aux changements d'état qu'effectue le code qui va être rejoué :

  • pour éviter les corruptions de données
  • pour éviter, à l'issue de la phase de debug, de remonter un contexte de reproduction d'un bug qui n'est pas celui d'origine mais un effet de bord de la manoeuvre
  • ...

Il faut faire attention à l'état actuel du programme et comprendre les effets de la reprise du code en un point donné car :

  • nous n'avons pas envie de libérer un verrou que nous n'avons pas acquis
  • nous n'avons pas envie d'utiliser l'instance d'une classe dont nous avons déjà appelé la méthode Dispose
  • nous n'avons pas envie d'utiliser une référence qui a été affecté à null après utilisation
  • ...

Les cas du verrou et de l'appel de Dispose sont intéressants car ils impliquent que l'utilisateur du debugger soit capable de faire attention aux instructions de bloc qui ne sont pas forcément très remarquables (telles que lock et using) et de se représenter mentalement ce que le compilateur va générer comme code à la compilation.
Dans le cas contraire, il va devoir comprendre pourquoi il obtient des exceptions étonnantes lors de la reprise d'exécution, telle que la très claire "System.Threading.SynchronizationLockException : Object synchronization method was called from an unsynchronized block of code." si le point d'exécution est repositionné en plein milieu d'un bloc lock alors que ce dernier avait été complété.

Car après tout, le mot clé lock n'est pas grand chose d'autre qu'une syntaxe plus concise pour laquelle le compilateur va générer l'équivalent d'un bloc try/finally utilisant la classe Monitor.

Si le mot clé lock n'avait pas existé, nous n'aurions pas écrit ça

private void DoSomething()
{
lock (this.lockTarget)
{
// ...
}
}

mais ça

private void DoSomething()
{
System.Threading.Monitor.Enter(this.lockTarget);
try
{
// ...
}
finally
{
System.Threading.Monitor.Exit(this.lockTarget);
}
}

Et là on s'aperçoit tout de suite mieux des conséquences d'un repositionnement du point d'exécution à hauteur du commentaire, donc dans le bloc try.
Avant de se risquer à utiliser "Set Next Statement" dans un code de ce genre, l'utilisateur du debugger devra aussi être capabable, le cas échéant, de se rendre compte des conséquences de l'exécution de code hors verrou qu'il a provoquée alors qu'elle n'était pas censée arriver afin de prendre la décision d'arrêter la session de debug à temps.

Le cas du bloc using est sensiblement identique à celui du bloc lock hormis le fait que la levée, sur les appels de méthodes de la classe, d'une exception ObjectDisposedException à même d'informer l'utilisateur du debugger de son erreur avant qu'il n'aille trop loin dépendra de l'implémentation du pattern Dispose et du design général de la classe.

Décidément, je n'aime vraiment pas ce "Set Next Statement"...

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: mardi 11 octobre 2011 01:40 par coq
Classé sous : , ,

Commentaires

cyril a dit :

mouarf, c'est marrant, moi, j'aime bien ca :)

C'est sur, faut faire gaffe et il ne faut pas reposer dessus. Je l'utilise surtout quand je loupe une étape de debug ou lorsque je veux "bypasser" un appel de fonction ou autre bout de code.

# octobre 11, 2011 22:47

coq a dit :

je suis un grand pessimiste :-)

# octobre 11, 2011 23:30

Rui a dit :

ouais, comme cyril, moi j'aime bien. Il faut bien sur être conscient des changements d'état impliqués mais presque tout le temps quand je l'utilise c'est pour faire un test rapide sans redémarrer le débug ou parce que j'ai loupé le point d'arret, etc... dans tous les cas, je pense que cela ne doit servir qu'à ça non?

# octobre 12, 2011 15:29

coq a dit :

Oui justement l'idée du post était de briser le mythe de la machine à remonter le temps sans conséquence, de rappeler qu'il fallait faire très attention et je voulais mettre en avant certains risques auxquels on ne pense pas forcément.

En tout cas personnellement je n'ai jamais réussi à faire confiance à cette fonctionnalité, mais je suis peut-être trop parano ;-)

# octobre 12, 2011 20:11
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Nouveau blog en anglais / New blog in english ! par Le blog de Patrick [MVP SharePoint] le il y a 47 minutes

- [ #Yammer ] From Mailbox to Yammer and back / De votre messagerie vers Yammer et retour ! par Le blog de Patrick [MVP SharePoint] le 09-15-2014, 11:31

- [ #Office 365 ] New service settings panel / Nouveau panneau de paramétrage des services par Le blog de Patrick [MVP SharePoint] le 09-11-2014, 08:50

- Problème de déploiement pour une démo SharePoint/TFS? par Blog de Jérémy Jeanson le 09-10-2014, 21:52

- [ #Office365 ] Delve first impressions / Premières impressions sur Delve par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 16:57

- [ #Office365 ] How to change Administration console language ? / Comment changer la langue de la console d’administration ? par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 08:25

- [ #SharePoint 2013 ] Suppression de bases de données en état “Pas de Réponse” par Le blog de Patrick [MVP SharePoint] le 09-04-2014, 14:10

- Changer l’adresse d’une ferme Office Web Apps associée à SharePoint par Blog de Jérémy Jeanson le 09-01-2014, 22:21

- Une ferme #SharePoint 2013 dans @Azure en quelques clics (1ère partie) ! par Le blog de Patrick [MVP SharePoint] le 08-28-2014, 18:52

- SharePoint 2013: Préparation de la migration - Création des site Templates dans 2010 et 2013 par Blog Technique de Romelard Fabrice le 08-20-2014, 16:31