This happens in .NET Framework 3.5, 32 bit, VS 2008.
C#:
namespace NesterovskyBros.Test { using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class CharAtUnitTest { private TestContext testContextInstance; public TestContext TestContext { get { return testContextInstance; } set { testContextInstance = value; } } [TestMethod] public void CharAtTest() { this.text = "1"; string token = Read(1, false); TestContext.WriteLine("token: {0}", token); } private string Read(int offset, bool flag) { string token = null; int c = 0; if (flag) { goto Whitespace; } Scan: c = CharAt(offset); switch(c) { case -1: { return "<Eof>"; } case '\'': { token = "Literal"; goto Literal; } } Whitespace: if (c == ' ') { return "Space"; } return "Unknown"; Literal: while(true) { int d = CharAt(offset); if (token != "Literal") { goto Scan; } if (d == c) { return token; } } } string text; private int CharAt(int offset) { string text = this.text; return (uint)offset >= (uint)text.Length ? -1 : text[offset]; } } }
In debug mode this test prints: "token: <Eof>". In release - "token: Unknown". The bug is so fragile that even slightest change in code removes it. Looking into disassembly we can see that the problem is near the switch:
Scan: c = CharAt(offset); /* Our old friend, CharAt(). Inlined! */ 00000017 mov edx,dword ptr [edi+8] 0000001a cmp dword ptr [edx+8],esi 0000001d jbe 00000032 0000001f cmp esi,dword ptr [edx+8] 00000022 jae 000000CE 00000028 movzx eax,word ptr [edx+esi*2+0Ch] 0000002d mov dword ptr [ebp-10h],eax 00000030 jmp 00000039 00000032 mov dword ptr [ebp-10h],0FFFFFFFFh /* Move -1 (four bytes) into stack. */ 00000039 movzx edx,word ptr [ebp-10h] /* Get two bytes into edx (0FFFFh) */ switch(c) 0000003d cmp edx,0FFFFFFFFh /* Never true. */ 00000040 je 0000004A 00000042 cmp dword ptr [ebp-10h],27h 00000046 je 0000005A 00000048 jmp 00000062 { case -1: { return "<Eof>"; 0000004a mov eax,dword ptr ds:[022EDE68h] 00000050 lea esp,[ebp-0Ch] 00000053 pop ebx 00000054 pop esi 00000055 pop edi 00000056 pop ebp 00000057 ret 4
This looks like a tremendous bug, like one of those shaking belief in computer's infallibility.
It would be nice if you would verify the case on your computer.
We believe that it is possible to use Console.WriteLine or Debug.WriteLine as a work around. We will look at doing this in future releases, though not in the upcoming one. ThanksVisual Studio Product Team
Thank you for taking the time to report this issue. The issue has been fixed and it will be part of a future release. It was caused by a bug in how the JIT determines when a cast is required upon the return value of an inlined functions.As a temporary work around you could make CharAt not inlineable (MethodImplAttribute can help with this), or you could reverse the comparison and the 2 branchs of the ?: operator, or you could add an explicit cast on the last operand of the ?: operator to force it to int.Grant RichinsCLR JIT Developer
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u