9

Oggi stavo eseguendo il debug di un mio codice che creava alcuni ExpressionTrees, li compila per chiamare i Delegati e li chiama in seguito, se necessario. Nel fare questo ho incontrato un FatalExecutionEngineError passo attraverso il codice:C# Expressions - FatalExecutionEngineError

FatalExecutionEngineError

All'inizio ero un po 'scioccata dal momento non avevo idea di quello che avrebbe potuto eventualmente sbagliato con le mie espressioni, sembravano tutti bene. Poi ho scoperto che questo avviene solo nella seguente situazione:

  • Method A è un metodo statico che viene chiamato e genera l'ExpressionTree, che può eventualmente contenere un Expression.Call() a Method A nuovamente. Quindi, dopo aver compilato il Lambda per ExpressionTree, il delegato generato (chiamiamolo Method B) potrebbe causare la ricorsione se lo chiamo all'interno di questo metodo ... (Method A ->[Generated]Method B ->Method A).

  • ... che è totalmente possibile nel mio scenario. Come descritto sopra stavo eseguendo il debug di questo pezzo di codice, quindi ho impostato un punto di interruzione in Method A.

  • La prima volta che Method A viene chiamato dal codice normale, il punto di interruzione viene colpito come al solito. Quando viene chiamato il numero Method B, il punto di interruzione viene eseguito una seconda volta, tutto è ancora in ordine.

  • Ma non appena lascio la seconda chiamata con il debugger scavalcando l'ultima riga, il FatalExecutionEngineError verifica.

Se faccio funzionare il codice senza debug, o non si sale nella chiamata ricorsiva a Method A, O se non passo oltre l'ultima riga del metodo, il problema non si verifica e il mio codice espressione è eseguito come previsto.

Non riesco a determinare se si tratta di un errore nel VS-Debugger o in .NET Framework, o se faccio qualcosa di orribilmente, orribilmente sbagliato che si presenta solo durante il debug delle righe pertinenti.

Ecco un codice di esempio molto semplice che è possibile eseguire senza problemi. Sto usando Visual Studio 2013 Prof Update 4 e .NET 4.5.1. Basta impostare un punto di interruzione nel DoSomething() e provare a passare alla fine - se possibile;)

Qualcuno può confermare un errore o la mia espressione è mal formata?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 
using System.Text; 
using System.Threading.Tasks; 

namespace ExpressionProblem 
{ 
    public class MainClass 
    { 
     public static void DoSomething(bool stop) 
     { 
      var method = typeof(MainClass).GetMethod(
       "DoSomething", 
       BindingFlags.Public | BindingFlags.Static, 
       Type.DefaultBinder, 
       new Type[] { typeof(bool) }, 
       null); 

      var expParam = Expression.Parameter(typeof(bool), "stop"); 
      var expCall = Expression.Call(null, method, expParam); 
      var lambda = Expression.Lambda(expCall, expParam); 
      var @delegate = lambda.Compile(); 
      if(!stop) 
      { 
       @delegate.DynamicInvoke(true); 
      } 
     } 

     public static void Main(string[] args) 
     { 
      DoSomething(false); 
     } 
    } 
} 
+0

Wow! Funziona/esplode! :-) – xanatos

+0

Ottengo la stessa cosa quando si utilizza VS2012 o VS2010, ma solo quando si utilizzano i passaggi descritti. Scoppia solo se passo in '@ delegate.DynamicInvoke', quindi continuo a scavalcare (non lasciandolo girare). – Shlomo

+2

Poiché funziona correttamente quando non esegue il debug, suppongo che sia un problema con il debugger. – Shlomo

risposta

6

Il codice di ripro è eccellente, questa bomba è affidabile. È altamente specifico per il motore di debug v4 per codice a 32 bit, non si verifica per il motore v2 o per il motore di debug a 64 bit. Sia il vecchio sia il nuovo motore v4 hanno questo problema.

Non vedo molto di nulla riconoscibile quando eseguo il debug del debugger, il codice che ha esito negativo si trova in mscorlib.dll con un lancio esplicito . Nulla di familiare, vedo alcuni suggerimenti per una classe non gestita denominata ILTree. Non è qualcosa che Microsoft condivide con noi, non è presente nel codice sorgente Reference Source, SSCLI20 o CoreCLR.

Questo è qualcosa di cui Microsoft deve preoccuparsi. Segnala il bug attraverso la connessione.microsoft.com. Un collegamento a questa domanda SO dovrebbe essere sufficiente per documentarlo. Fammi sapere se non vuoi prenderti il ​​tempo per farlo e me ne occuperò io.

Nel frattempo si ha una soluzione decente per continuare, basta lasciare che il programma funzioni in modalità 64 bit rimuovendo la forzatura del jitter. Progetto + Proprietà, scheda Costruisci, deselezionare l'opzione "Prefer 32-bit" e selezionare AnyCPU per l'obiettivo della piattaforma. Si prega di seguire quando si sente indietro da Microsoft.

+4

Grazie mille Hans. Ogni volta che rimango interdetto davanti a un problema, all'improvviso vieni caricato con un'analisi così dettagliata :) Ho inviato il bug report qui: https://connect.microsoft.com/VisualStudio/feedback/details/1148770 – PuerNoctis

Problemi correlati