Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is code behavior different in release & debug mode?

Consider the following 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; } 

The result in Debug mode is: 100,100,100,100,100. But in Release mode it is: 100,100,100,100,0.

What is happening?

It was tested using .NET framework 4.7.1 and .NET Core 2.0.0.

like image 290
Ashkan Nourzadeh Avatar asked Dec 01 '17 10:12

Ashkan Nourzadeh


1 Answers

This appears to be a JIT bug; I've tested with:

// ... existing code unchanged for (int i = 0; i < N - Old.Length; i++) {     // Console.WriteLine(i); // <== comment/uncomment this line     dd[i] = d; } 

and adding the Console.WriteLine(i) fixes it. The only IL change is:

// ... L_0040: ldc.i4.0  L_0041: stloc.3  L_0042: br.s L_004d L_0044: ldarg.0  L_0045: ldind.ref  L_0046: ldloc.3  L_0047: ldloc.1  L_0048: stelem.r8  L_0049: ldloc.3  L_004a: ldc.i4.1  L_004b: add  L_004c: stloc.3  L_004d: ldloc.3  L_004e: ldarg.1  L_004f: ldloc.0  L_0050: ldlen  L_0051: conv.i4  L_0052: sub  L_0053: blt.s L_0044 L_0055: ret  

vs

// ... L_0040: ldc.i4.0  L_0041: stloc.3  L_0042: br.s L_0053 L_0044: ldloc.3  L_0045: call void [System.Console]System.Console::WriteLine(int32) L_004a: ldarg.0  L_004b: ldind.ref  L_004c: ldloc.3  L_004d: ldloc.1  L_004e: stelem.r8  L_004f: ldloc.3  L_0050: ldc.i4.1  L_0051: add  L_0052: stloc.3  L_0053: ldloc.3  L_0054: ldarg.1  L_0055: ldloc.0  L_0056: ldlen  L_0057: conv.i4  L_0058: sub  L_0059: blt.s L_0044 L_005b: ret  

which looks exactly right (the only difference is the extra ldloc.3 and call void [System.Console]System.Console::WriteLine(int32), and a different but equivalent target for br.s).

It'll need a JIT fix, I suspect.

Environment:

  • Environment.Version: 4.0.30319.42000
  • <TargetFramework>netcoreapp2.0</TargetFramework>
  • VS: 15.5.0 Preview 5.0
  • dotnet --version: 2.1.1
like image 115
Marc Gravell Avatar answered Oct 05 '22 07:10

Marc Gravell