5Fermer7
GoldenCrystalLe 14/08/2016 à 00:47
Nan mais c'est forcément un bug dans ton programme… Le JIT peut avoir des bugs (c'est arrivé dans le passé, c'est certainement encore le cas aujourd'hui) mais c'est rarement simple, vu que la majorité des fonctions sont utilisées par les développeurs (et par extension leurs utilisateurs) quotidiennement.

Ce que tu peux faire pour déboguer ça c'est de générer un assembly "RunAndSave" au lieu d'une DynamicMethod (c'est un peu plus de code, que tu supprimeras une fois ton boulot de correction fini, mais c'est la meilleure façon de faire)
Du coup, tu dois pouvoir aussi y générer des infos de débogage, ce qui peut (ou pas aider) à voir ce qui se passe dans Visual Studio. (Eventuellement…)
Mais surtout, ça va te permettre de passer ton code à peverify.exe qui détecte bien plus de choses que le runtime. (Le runtime fait beaucoup de vérifications, mais il va en sauter quelques unes non essentielles, et puis même si il ne les saute pas, il ne te dira pas toujours précisément ce qui ne va pas)
En parallèle de ça, je t'encourage fortement à passer ta DLL générée dans un décompilateur C# (Oui, ces choses ont une vraie utilité parfaitement légale tongue) comme ILSpy, vu que ça doit être le meilleur gratuit du moment. L'idée c'est qu'il doit arriver à comprendre ton code IL*, et à te ressortir l'algorithme que tu as implémenté sous forme de C#: ça te permettra de vérifier d'un rapide coup d'œil que tout se fait exactement comme tu le voulais. smile

* Attention, ILSpy peut aussi se foirer dans certains cas, ce n'est pas un vérificateur IL.
Bugs de décompilation

J'ai quelques exemples en tête où ILSpy/autres se foire à la décompilation, mais ce n'est pas exhaustif smile

Ceux où il ne décompile "pas assez" sont nombreux, mais rarement très graves, vu que ça n'impacte pas la logique du code:
  • Mélanger async et dynamic dans la même méthode, ça peut vite paumer la décompilation. (Ce sont deux domaines qui provoquent une réécriture de code massive de la part du compilateur C#, chacun à leur façon)
  • Faire des switch avec trop de cas possibles (ça a peut être été corrigé depuis, ça fait très longtemps que je l'ai constaté)
  • De manière générale, toutes les structures de code un peu trop complexes risquent de faire apparaître des goto au lieu de l'enchevêtrement de structures natives. (Mais c'est logique, vu que tout est basé sut goto à la fin)

Par contre c'est l'algorithme de simplification du code qui peut se foirer légèrement ou lourdement. (Donc, à l'inverse des cas où il n'en fait pas assez)
Parfois, des détails vont carrément disparaître du code décompilé, produisant soit du code qui ne compile pas, soit du code qui ne correspond pas à l'original.
  • En C# l'opérateur ternaire est vraiment chiant, car totalement inflexible au niveau de la détermination de type: souvent on est obligé de caster une ou l'autre des deux branches vers le bon type pour que le code compile. Mais des fois, ce cast saute à la décompilation. (Typiquement dans les cas où le cast va disparaitre en IL parce qu'il servait réellement à rien, et ces cas sont assez nombreux)
  • Des cas où le code est un peu tordu car codé plus en IL qu'en C# et où le décompialteur va interpréter un bout de code comme un autre pattern à tort. (Typiquement, le compilateur C# ne produit pas un code IL efficace. "Pas" ne veut pas dire "jamais", mais il y a plein d'optimisations impossibles à faire par le JIT que le compilateur C# ne fait pas, alors qu'il pourrait les faire, et plein d'optimisations que le JIT sait faire et que le compilateur C# ne s'embête pas à faire, et qui génère un IL plus gros que nécessaire. Le code IL généré à la main ne possède pas nécessairement ces mêmes défauts, mais ne rentre de fait pas dans les mêmes stéréotypes que le code C#)