Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# 'is' type check on struct - odd .NET 4.0 x86 optimization behavior

Update: I have filed a bug report with Microsoft Connect, please vote for it!

Update 2: Microsoft have marked the bug report as fixed

Posted by Microsoft on 18/08/2010 at 17:25

This bug will be fixed in a future version of the runtime. I'm afraid it's too early to tell if that will be in a service pack or the next major release.

Since upgrading to VS2010 I'm getting some very strange behavior with the 'is' keyword.

The program below (test.cs) outputs True when compiled in debug mode (for x86) and False when compiled with optimizations on (for x86). Compiling all combinations in x64 or AnyCPU gives the expected result, True.

All combinations of compiling under .NET 3.5 give the expected result, True.

I'm using the batch file below (runtest.bat) to compile and test the code using various combinations of compiler .NET framework.

  • Has anyone else seen these kind of problems under .NET 4.0?
  • Does everyone else see the same behavior as me on their computer when running runtests.bat?
  • @$@#$??

  • Is there a fix for this?

test.cs

using System;  public class Program {     public static bool IsGuid(object item)     {         return item is Guid;     }       public static void Main()     {         Console.Write(IsGuid(Guid.NewGuid()));     } } 

runtest.bat

@echo off  rem Usage: rem   runtest         -- runs with csc.exe x86 .NET 4.0 rem   runtest 64      -- runs with csc.exe x64 .NET 4.0 rem   runtest v3.5    -- runs with csc.exe x86 .NET 3.5 rem   runtest v3.5 64 -- runs with csc.exe x64 .NET 3.5  set version=v4.0.30319 set platform=Framework  for %%a in (%*) do (   if "%%a" == "64" (set platform=Framework64)   if "%%a" == "v3.5" (set version=v3.5) )  echo Compiler: %platform%\%version%\csc.exe set csc="C:\Windows\Microsoft.NET\%platform%\%version%\csc.exe"  set make=%csc% /nologo /nowarn:1607 test.cs rem CS1607: Referenced assembly targets a different processor rem This happens if you compile for x64 using csc32, or x86 using csc64  %make% /platform:x86 test.exe echo  =^> x86  %make% /platform:x86 /optimize test.exe echo  =^> x86 (Optimized)  %make% /platform:x86 /debug test.exe echo  =^> x86 (Debug)  %make% /platform:x86 /debug /optimize test.exe echo  =^> x86 (Debug + Optimized)  %make% /platform:x64 test.exe echo  =^> x64  %make% /platform:x64 /optimize test.exe echo  =^> x64 (Optimized)  %make% /platform:x64 /debug test.exe echo  =^> x64 (Debug)  %make% /platform:x64 /debug /optimize test.exe echo  =^> x64 (Debug + Optimized)  %make% /platform:AnyCPU test.exe echo  =^> AnyCPU  %make% /platform:AnyCPU /optimize test.exe echo  =^> AnyCPU (Optimized)  %make% /platform:AnyCPU /debug test.exe echo  =^> AnyCPU (Debug)  %make% /platform:AnyCPU /debug /optimize test.exe echo  =^> AnyCPU (Debug + Optimized) 

Test Results

When running the runtest.bat I get the following results on my Win7 x64 install.

> runtest 32 v4.0 Compiler: Framework\v4.0.30319\csc.exe False => x86 False => x86 (Optimized) True => x86 (Debug) False => x86 (Debug + Optimized) True => x64 True => x64 (Optimized) True => x64 (Debug) True => x64 (Debug + Optimized) True => AnyCPU True => AnyCPU (Optimized) True => AnyCPU (Debug) True => AnyCPU (Debug + Optimized)  > runtest 64 v4.0 Compiler: Framework64\v4.0.30319\csc.exe False => x86 False => x86 (Optimized) True => x86 (Debug) False => x86 (Debug + Optimized) True => x64 True => x64 (Optimized) True => x64 (Debug) True => x64 (Debug + Optimized) True => AnyCPU True => AnyCPU (Optimized) True => AnyCPU (Debug) True => AnyCPU (Debug + Optimized)  > runtest 32 v3.5 Compiler: Framework\v3.5\csc.exe True => x86 True => x86 (Optimized) True => x86 (Debug) True => x86 (Debug + Optimized) True => x64 True => x64 (Optimized) True => x64 (Debug) True => x64 (Debug + Optimized) True => AnyCPU True => AnyCPU (Optimized) True => AnyCPU (Debug) True => AnyCPU (Debug + Optimized)  > runtest 64 v3.5 Compiler: Framework64\v3.5\csc.exe True => x86 True => x86 (Optimized) True => x86 (Debug) True => x86 (Debug + Optimized) True => x64 True => x64 (Optimized) True => x64 (Debug) True => x64 (Debug + Optimized) True => AnyCPU True => AnyCPU (Optimized) True => AnyCPU (Debug) True => AnyCPU (Debug + Optimized) 

tl;dr

like image 629
Jacob Stanley Avatar asked May 12 '10 13:05

Jacob Stanley


1 Answers

I worked up a similar example that fails the same way:

using System; using System.Runtime.CompilerServices;  public class Program {   static void Main() {     Console.Write(Verify(Test.Create()));     Console.ReadLine();   }   //[MethodImpl(MethodImplOptions.NoInlining)]   static bool Verify(IDisposable item) {     return item is Test;   }   struct Test : IDisposable {     public void Dispose() { }     public static Test Create() { return new Test(); }   } } 

It is a JIT optimizer bug. Can't quite put the finger on it, it optimizes the code heavily. But it looks to me like it gets in trouble when it optimizes the boxing conversion away. Pretty serious bug, frankly.


This bug has been fixed, I can no longer repro it. My current version of clrjit.dll is 4.0.30319.237 dated May 17th 2011. I can't tell exactly what update repaired it. I got a security update on Aug 5th 2011 that updated clrjit.dll to revision 235 with a date of Apr 12, that would be the earliest.

like image 155
Hans Passant Avatar answered Oct 17 '22 23:10

Hans Passant