Why would finding a type’s initializer throw a NullReferenceException?

This has got me stumped. I was trying to optimize some tests for Noda Time, where we have some type initializer checking. I thought I’d find out whether a type has a type initializer (static constructor or static variables with initializers) before loading everything into a new AppDomain. To my surprise, a small test of this threw NullReferenceException – despite there being no null values in my code. It only throws the exception when compiled with no debug information.

Here’s a short but complete program to demonstrate the problem:

using System;

class Test
{
    static Test() {}

    static void Main()
    {
        var cctor = typeof(Test).TypeInitializer;
        Console.WriteLine("Got initializer? {0}", cctor != null);
    }    
}

And a transcript of compilation and output:

c:\Users\Jon\Test>csc Test.cs
Microsoft (R) Visual C# Compiler version 4.0.30319.17626
for Microsoft (R) .NET Framework 4.5
Copyright (C) Microsoft Corporation. All rights reserved.


c:\Users\Jon\Test>test

Unhandled Exception: System.NullReferenceException: Object reference not set to
an instance of an object.
   at System.RuntimeType.GetConstructorImpl(BindingFlags bindingAttr, Binder bin
der, CallingConventions callConvention, Type[] types, ParameterModifier[] modifi
ers)
   at Test.Main()

c:\Users\Jon\Test>csc /debug+ Test.cs
Microsoft (R) Visual C# Compiler version 4.0.30319.17626
for Microsoft (R) .NET Framework 4.5
Copyright (C) Microsoft Corporation. All rights reserved.


c:\Users\Jon\Test>test
Got initializer? True

Now you’ll notice I’m using .NET 4.5 (the release candidate) – which may be relevant here. It’s somewhat tricky for me to test it with the various other original frameworks (in particular “vanilla” .NET 4) but if anyone else has easy access to machines with other frameworks, I’d be interested in the results.

Other details:

  • I’m on an x64 machine, but this problem occurs with both x86 and x64 assemblies
  • It’s the “debug-ness” of the calling code which makes a difference – even though in the test case above it’s testing it on its own assembly, when I tried this against Noda Time I didn’t have to recompile NodaTime.dll to see the differences – just Test.cs which referred to it.
  • Running the “broken” assembly on Mono 2.10.8 doesn’t throw

Any ideas? Framework bug?

EDIT: Curiouser and curiouser. If you take out the Console.WriteLine call:

using System;

class Test
{
    static Test() {}

    static void Main()
    {
        var cctor = typeof(Test).TypeInitializer;
    }    
}

It now only fails when compiled with csc /o- /debug-. If you turn on optimizations, (/o+) it works. But if you include the Console.WriteLine call as per the original, both versions will fail.

2 Answers
2

Leave a Comment