2009-07-18 23 views
20

Il metodo System.Threading.ConcurrentQueue.TryDequeue ha emesso un'eccezione l'altro giorno che mi ha colto di sorpresa. Ecco l'analisi dello stack:Bug in System.Random constructor?

System.OverflowException: Negating the minimum value of a twos complement number is invalid. 
    at System.Math.AbsHelper(Int32 value) 
    at System.Random..ctor(Int32 Seed) 
    at System.Threading.Collections.ConcurrentQueue`1.TryDequeueCore(T& result) 
    at System.Threading.Collections.ConcurrentQueue`1.TryDequeue(T& result) 
    at MyProgram.ThreadProc() in c:\MyProgram\Main.cs:line 118 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

In un primo momento ho pensato che il problema era che TryDequeueCore chiamato il Random costruttore con un pessimo affare. Ma ulteriori indagini rivelano che TryDequeueCore chiama il costruttore predefinito. Sembra a me come l'errore è nel Random costruttore:

.method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
{ 
    // Code size  12 (0xc) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: call  int32 System.Environment::get_TickCount() 
    IL_0006: call  instance void System.Random::.ctor(int32) 
    IL_000b: ret 
} // end of method Random::.ctor 

quanto la documentazione per la proprietà System.Environment.TickCount dice:

Il valore di questa proprietà è derivato dal timer di sistema e viene memorizzato come un numero intero con segno a 32 bit. Di conseguenza, se il sistema viene eseguito continuamente, TickCount incrementerà da zero a Int32 .. ::. MaxValue per circa 24,9 giorni, quindi passare a Int32 .. ::. MinValue, che è un numero negativo , quindi incrementare indietro a zero durante i prossimi 24,9 giorni.

Quindi, se si chiama il costruttore Random durante quel periodo di un millisecondo (dopo che il sistema è stato per int.MaxValue millisecondi), che sta per lanciare questa eccezione.

Qualcuno ha una soluzione alternativa? Per il mio codice personale, posso creare un metodo CreateRandom che ottiene il valore TickCount e lo controlla per int.MinValue. Ma cosa fare del codice su cui non ho controllo?

Spero che il team RTL lo risolva in .NET 4.0.

Aggiornamento 2009/07/22: Il team BCL ha risposto al bug e ha affermato che è stato risolto per la prossima versione.

+2

Spero tu abbia fatto un bug report :) – n3rd

+2

Wow, bella indagine. – GManNickG

+1

Bug segnalato in Microsoft Connect. https://connect.microsoft.com/VisualStudio Bug # 475447. –

risposta

4

try/catch e riprovare un millesimo di secondo dopo sembra solo l'unica cosa che puoi fare fino a quando questo bug non viene corretto.

+0

Forse. Ma prendi il caso di ConcurrentQueue.TryDequeue. Questo metodo non dovrebbe generare eccezioni. Ora devo racchiudere tutte le chiamate su TryDequeue in un blocco try/catch. E che dire del codice che non conosco usa Random? –

+0

Finché in fondo nelle librerie di sistema c'è un bug che causa il lancio di eccezioni quando non si dovrebbe mai essere, cos'altro si può fare con altro codice al di fuori del proprio controllo, a cui non si hanno fonti e che POTREBBE chiamare il system lib in questione? A meno che non sia possibile passare a uno stack open source, in cui è possibile correggere gli errori una volta individuati, si è inevitabilmente impietositi dal fornitore del codice proprietario. try/catch è solo l'unica cosa che puoi fare, e sicuramente non è perfetto, ma che altro? –