2015-11-04 22 views
6

Ricevo "System.NullReferenceException: riferimento oggetto non impostato su un'istanza di un oggetto." sul mio rilascio build. Ho creato un'applicazione di esempio che imita ciò che c'è nel mio codice di produzione.NullReferenceException in VS2015 C++/CLI Release Build

void Abc::LogService::Log(String^ message) 
{ 
    try 
    {  
     int ret = DoProcessing(message); 
     Exception^ ex; 
     if (ret == 0) 
     { 
      ex = gcnew ArgumentException("Processing done."); 
     } 
     else 
     { 
      ex = gcnew ArgumentNullException("message", "Null args"); 
     } 
     throw ex; 
    } 
    finally 
    { 
     //do someother thing. 
    } 
} 

Con il codice di cui sopra, si segnala la linea di deroga sia: at Abc.LogService.Log(String message) in logservice.cpp:line 19 che corrisponde alla throw ex; dichiarazione nel codice.

Il MSIL nel build di rilascio per questa funzione appare come:

.method public hidebysig instance void Log(string message) cil managed 
{ 
    // Code size  46 (0x2e) 
    .maxstack 4 
    .locals ([0] class [mscorlib]System.Exception V_0, 
      [1] class [mscorlib]System.Exception ex) 
    .try 
    { 
    IL_0000: ldarg.0 
    IL_0001: ldarg.1 
    IL_0002: call  instance int32 Abc.LogService::DoProcessing(string) 
    IL_0007: ldnull 
    IL_0008: stloc.1 
    IL_0009: brtrue.s IL_0018 
    IL_000b: ldstr  "Processing done." 
    IL_0010: newobj  instance void [mscorlib]System.ArgumentException::.ctor(string) 
    IL_0015: stloc.0 
    IL_0016: br.s  IL_0028 
    IL_0018: ldstr  "message" 
    IL_001d: ldstr  "Null args" 
    IL_0022: newobj  instance void [mscorlib]System.ArgumentNullException::.ctor(string, 
                        string) 
    IL_0027: stloc.0 
    IL_0028: ldloc.1 
    IL_0029: throw 
    IL_002a: leave.s IL_002d 
    } // end .try 
    finally 
    { 
    IL_002c: endfinally 
    } // end handler 
    IL_002d: ret 
} // end of method LogService::Log 

Dal codice MSIL, dimostra che per la dichiarazione IL_0028, si carica di un valore nullo e chiama il tiro nella dichiarazione successiva. La parte strana è che ciò accade solo se ho il blocco try-finally. La compilazione del debug del codice precedente funziona correttamente.

Suona come un bug nel toolkit VS1015 v140?

risposta

3

Sì, questo è un bug di ottimizzazione. Piuttosto insolito, il primo che ho visto per C++/CLI, una lingua in cui il jitter dovrebbe fare il sollevamento pesi. Sembra che sia scattato dichiarando la variabile ex all'interno del try-block, facendola soffocare sulla garanzia di inizializzazione. Sembra un bug di analisi del flusso.

brevi a partire da compilare con/Od, uno soluzione è spostare la variabile fuori dal blocco try

void Log(String^ message) { 
    Exception^ ex; 
    try { 
     // etc... 
} 

producendo anche molto meglio MSIL, eliminando completamente la variabile:

.method public hidebysig instance void Log(string message) cil managed 
{ 
    // Code size  41 (0x29) 
    .maxstack 4 
    .try 
    { 
    IL_0000: ldarg.0 
    IL_0001: ldarg.1 
    IL_0002: call  instance int32 Test::DoProcessing(string) 
    IL_0007: brtrue.s IL_0015 
    IL_0009: ldstr  "Processing done." 
    IL_000e: newobj  instance void [mscorlib]System.ArgumentException::.ctor(string) 
    IL_0013: br.s  IL_0024 
    IL_0015: ldstr  "message" 
    IL_001a: ldstr  "Null args" 
    IL_001f: newobj  instance void [mscorlib]System.ArgumentNullException::.ctor(string, 
                        string) 
    IL_0024: throw 
    IL_0025: leave.s IL_0028 
    } // end .try 
    finally 
    { 
    IL_0027: endfinally 
    } // end handler 
    IL_0028: ret 
} // end of method Test::Log 

bug Optimizer succhiare, puoi segnalarlo a connect.microsoft.com

Problemi correlati