Betrachten Sie den folgenden Code:
private static void Main(string[] args)
{
var ar = new double[]
{
100
};
FillTo(ref ar, 5);
Console.WriteLine(string.Join(",", ar.Select(a => a.ToString()).ToArray()));
}
public static void FillTo(ref double[] dd, int N)
{
if (dd.Length >= N)
return;
double[] Old = dd;
double d = double.NaN;
if (Old.Length > 0)
d = Old[0];
dd = new double[N];
for (int i = 0; i < Old.Length; i++)
{
dd[N - Old.Length + i] = Old[i];
}
for (int i = 0; i < N - Old.Length; i++)
dd[i] = d;
}
Das Ergebnis im Debug-Modus ist: 100.100.100.100.100. Im Release-Modus ist dies jedoch: 100.100.100.100,0.
Was ist los?
Es wurde mit .NET Framework 4.7.1 und .NET Core 2.0.0 getestet.
Console.WriteLine(i);
in die letzte Schleife (dd[i] = d;
) "behebt" es, was auf einen Compiler- oder JIT-Fehler hindeutet. Blick in die IL ...if (dd.Length >= N) return;
, was eine einfachere Reproduktion sein kann.Antworten:
Dies scheint ein JIT-Fehler zu sein. Ich habe getestet mit:
und die
Console.WriteLine(i)
Korrekturen hinzufügen . Die einzige IL-Änderung ist:vs.
Das sieht genau richtig aus (der einzige Unterschied ist das Extra
ldloc.3
undcall void [System.Console]System.Console::WriteLine(int32)
, und ein anderes, aber gleichwertiges Ziel fürbr.s
).Ich vermute, es wird einen JIT-Fix brauchen.
Umgebung:
Environment.Version
: 4.0.30319.42000<TargetFramework>netcoreapp2.0</TargetFramework>
dotnet --version
: 2.1.1quelle
Es ist in der Tat ein Montagefehler. x64, .net 4.7.1, Release Build.
Demontage:
Das Problem ist unter der Adresse 00007FF942690AFD, der jg 00007FF942690AE7. Es springt zurück, wenn ebx (das 4 enthält, den Endwert der Schleife) größer (jg) ist als eax, der Wert i. Dies schlägt natürlich fehl, wenn es 4 ist, sodass nicht das letzte Element in das Array geschrieben wird.
Es schlägt fehl, weil es den Registerwert von i (eax, bei 0x00007FF942690AF9) enthält und es dann mit 4 überprüft, aber es muss diesen Wert noch schreiben. Es ist etwas schwierig zu bestimmen, wo genau sich das Problem befindet, da es möglicherweise das Ergebnis der Optimierung von (N-Old.Length) ist, da der Debug-Build diesen Code enthält, der Release-Build dies jedoch vorberechnet. Das müssen die Leute also reparieren;)
quelle