none
Assembly.GetTypes() hangs infinitely on .NET 4.0 RRS feed

  • Question

  • Hello,

    We're developing a .NET 4.0 WPF application and we ran into very strange problem. We're simply calling Assembly.GetTypes but for some reason it never completes. Also, it is using 100% of one processor core.

    Even the following simple console application never completes:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var assembly = typeof(MyLibrary.MyType).Assembly;
                var types = assembly.GetTypes();
            }
        }
    }

    In this case MyLibrary.MyType lives in another assembly to which I have reference in this console application. Also, the assembly has many other references but I have understood that if there were any problems in loading these other references, an exception should be thrown instead of hanging infinitely.

    I turned Just My Code off from debugging options and it seems that following line is causing the problem:

    SystemEvents.cs line 1569 int ret = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE);

    What could be the problem? Is this a bug in .NET 4.0? Is there a way to debug this somehow? On a computer that has .NET 4.5 installed this works perfectly. We have tested this both on Win7 and Win8.

    Thanks!

    Tuesday, May 21, 2013 11:28 AM

All replies

  • We use this type of code all the time and we're not having any issues.  The call you mention is a blocking call waiting for a Windows message.  AFAIK GetTypes wouldn't call that as GetTypes isn't blocking on anything.  Is this problem occurring only on 1 machine or several?  Debug the app and when it hits the GetTypes call then break in using the debugger and get the call stack information.

    Does the problem occur with a different assembly?  Do you have any static constructors that are doing lengthy work that could stall the load of the types?

    Michael Taylor
    http://msmvps.com/blogs/p3net

    Tuesday, May 21, 2013 2:17 PM
    Moderator
  • The problem is occuring on every machine that is using .NET 4.0 (we have tested on 4 different computers). And of course I have used GetTypes() previously without any problems and this problem is occuring only when referencing our application's DLLs.

    So it is possible that static constructors are executed when GetTypes() call is made? If this is the case that could be the problem but still it doesn't explain why it works perfectly on same machine with .NET 4.5 but not with .NET 4.0 (especially when all our DLLs are compiled to target 4.0).

    On the other hand, Jon Skeet's article (http://csharpindepth.com/Articles/General/Beforefieldinit.aspx) suggests that user-defined static constructors shouldn't be called unless 1) class is instantiated or 2) static method is called. And I don't believe that GetTypes() is doing either of those..? Also, call stacks do not suggest that user code is being executed.

    Call stacks for aforementioned console application:

    MAIN THREAD

    [Managed to Native Transition] mscorlib.dll!System.Reflection.RuntimeModule.GetTypes() + 0x5 bytes mscorlib.dll!System.Reflection.Assembly.GetTypes() + 0x4f bytes ConsoleApplication1.exe!ConsoleApplication1.Program.Main(string[] args) Line 13 + 0xb bytes [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x6d bytes Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2a bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x63 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool ignoreSyncCtx) + 0xb0 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x2c bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes [Native to Managed Transition]

    WORKER THREAD (name: .NET SystemEvents)

    [In a sleep, wait, or join] System.dll!Microsoft.Win32.SystemEvents.WindowThreadProc() Line 1572 + 0xa bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x63 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool ignoreSyncCtx) + 0xb0 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x2c bytes mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes [Native to Managed Transition]

    So basically main thread it is just idling in

    System.Reflection.RuntimeModule.GetTypes()

    Using .NET Reflector it seems that it is implemented simply as

    [SecuritySafeCritical]
    public override Type[] GetTypes()
    {
        return GetTypes(this.GetNativeHandle());
    }
    
    

    Any more ideas?



    Wednesday, May 22, 2013 8:34 AM
  • I wouldn't have expected GetTypes to lock up as all it really does is load and enumerate type metadata.  However stranger things have happened.  Static ctors will only be called when the type is needed by the runtime.  Getting type metadata shouldn't trigger that process but not everything an assembly does can be prevented without switching to the reflection-only context.  Given your specific sample code this is probably the first time the assembly has been seen so it has triggered the loading of the assembly which has some processing overhead.  However you're successfully calling GetTypes so the assembly is already loaded so we can eliminate issues with assembly loading.

    The SystemEvents thread is supposed to be a blocking call so that one is fine.  The issue is on your main thread if that is where your app is hanging.  It appears that it is in the process of enumerating the metadata. 

    To clarify:
    1) Your Myclass assembly is built against the .NET v4.0 framework correct? 
    2) The assembly has no dependencies on other assemblies that are potentially targeting .NET v4.5?
    3) The machines that don't work do not have .NET v4.5 installed?
    4) The assembly is a C# or VB assembly and not C++/CLI or similar?
    5) Can you use a GetType overload to get a specific type?
    6) Can you narrow down the search to, say, only static types to see if that comes back?

    Michael Taylor
    http://msmvps.com/blogs/p3net

    Wednesday, May 22, 2013 1:52 PM
    Moderator
  • I would suggest you check for loaded assemblies first. If your assembly is not loaded try loading it using path. This way you will have more ammo to solve issues.

    Thanks.


    Mohammad Saidul Karim

    Thursday, May 23, 2013 3:30 AM
  • I wouldn't have expected GetTypes to lock up as all it really does is load and enumerate type metadata.  However stranger things have happened.  Static ctors will only be called when the type is needed by the runtime.  Getting type metadata shouldn't trigger that process but not everything an assembly does can be prevented without switching to the reflection-only context.  Given your specific sample code this is probably the first time the assembly has been seen so it has triggered the loading of the assembly which has some processing overhead.  However you're successfully calling GetTypes so the assembly is already loaded so we can eliminate issues with assembly loading.

    The SystemEvents thread is supposed to be a blocking call so that one is fine.  The issue is on your main thread if that is where your app is hanging.  It appears that it is in the process of enumerating the metadata. 

    To clarify:
    1) Your Myclass assembly is built against the .NET v4.0 framework correct? 
    2) The assembly has no dependencies on other assemblies that are potentially targeting .NET v4.5?
    3) The machines that don't work do not have .NET v4.5 installed?
    4) The assembly is a C# or VB assembly and not C++/CLI or similar?
    5) Can you use a GetType overload to get a specific type?
    6) Can you narrow down the search to, say, only static types to see if that comes back?

    Michael Taylor
    http://msmvps.com/blogs/p3net

    Thank you for your reply!

    To answer your questions:

    1. Yes, MyClass assembly is built against the .NET v4.0 framework
    2. MyClass assembly does not have any dependencies on other assemblies that are targeting .NET v4.5.
    3. The machines that doesn't work do not have .NET v4.5 installed. The application works immediately after .NET v4.5 is installed and stops working immediately after .NET v4.5 is removed. Also, if I remove the GetTypes() call everything is working well on these machines that do not have .NET v4.5 installed (but have .NET v4.0) (well everything except the functionality which is depending on GetTypes being called...)
    4. The assembly is plain C#-assembly.
    5. See below.
    6. See below.

    I ran some tests related to bullets 5 and 6. I created a list of all types in that DLL using .NET v4.5 and called GetType individually for each type using .NET v4.0. Results: GetType() worker well for all types except one, for which it never completed.

    A bit more info about our project: although we are targeting .NET v4.0 we are still using the new 'async' feature of C# 5.0 with Microsoft's AsyncTargetingPack. The type which is causing the problem is one of the classes automatically generated by C# compiler to provide the async feature (e.g. its name is MyLibrary.MyClass+<MyFunctionName>d__86 and we have method public static async Task MyFunctionName() in class MyLibrary.MyClass).

    Now some more interesting facts. I played around this method and modified it so that GetType() would eventually complete without problems. I noticed following things:

    1. The method is referencing another assembly multiple times (by using types defined in that assembly). The referenced assembly is targeting .NET v4.0.
    2. The less that there are these references, the faster GetType() call finishes!
    3. However, even a small number of references makes the GetType() hang for long time

    Some statistics:

    public static async Task MyFunctionName()
    {
        var tmp1 = OtherLibrary.Enum1.Value1;
        await Task.Delay(0);
    }
    
    -> GetType() for 'MyLibrary.MyClass+<MyFunctionName>d__86' finishes in ~6 seconds

    public static async Task MyFunctionName() { var tmp1 = OtherLibrary.Enum1.Value1;

    var tmp2 = OtherLibrary.AnotherEnum.Value1; await Task.Delay(0); } -> GetType() for 'MyLibrary.MyClass+<MyFunctionName>d__86' finishes in ~13 seconds

    public static async Task MyFunctionName() { var tmp1 = OtherLibrary.Enum1.Value1;

    var tmp2 = OtherLibrary.AnotherEnum.Value1;

    var tmp3 = OtherLibrary.YetAnotherEnum1.Value1;

    var tmp4 = OtherLibrary.YetAnotherEnum2.Value2; await Task.Delay(0); } -> I waited for about 15 minutes and GetType() did not finish.

    So actually it seems that in original scenario, GetTypes() call would eventually finish if I just waited long enough. However I'm not sure would the universe collapse before that...

    To me this is looking more and more like a a bug or 'unfavorable feature' in .NET v4.0. I wonder if there are any workarounds since we really want to target .NET v4.0. The reason why we are using GetTypes() is that we have dependency injection container for which we are registering types via simple auto-registration mechanism that uses GetTypes(). Of course we could skip auto-registration and do that manually but that would be a big burden.

    Thursday, May 23, 2013 12:01 PM
  • Most compiler-related changes work against the existing framework but there are a few that won't.  Async was mostly compiler-specific but there are a few things that MS said it required changes in the framework to support.  If you're using async then you are going to have to use .NET 4.5.  Alternatively if you must stick with .NET 4 and you must use the async keyword then download the RTM version of the Async Targeting pack which, from my understanding, will allow you to use async in .NET 4.

    Therefore this is not a bug in the framework as you're using a .NET 4.5 feature with .NET 4.  You were fortunate that you only ran across this problem.  Nevertheless it is not a supported scenario so you'll need to use the ATP to get it to work properly.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    Thursday, May 23, 2013 1:53 PM
    Moderator
  • Most compiler-related changes work against the existing framework but there are a few that won't.  Async was mostly compiler-specific but there are a few things that MS said it required changes in the framework to support.  If you're using async then you are going to have to use .NET 4.5.  Alternatively if you must stick with .NET 4 and you must use the async keyword then download the RTM version of the Async Targeting pack which, from my understanding, will allow you to use async in .NET 4.

    Therefore this is not a bug in the framework as you're using a .NET 4.5 feature with .NET 4.  You were fortunate that you only ran across this problem.  Nevertheless it is not a supported scenario so you'll need to use the ATP to get it to work properly.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    We are already using Async Targeting Pack as I mentioned in my post so that doesn't really explain the problem. With ATP async should be fully supported and certainly shouldn't cause problems like this.
    Thursday, May 23, 2013 2:13 PM
  • In that case I would wager it is an issue with ATP.  You should report the issue to MS.  I don't know if Connect is the appropriate place for that or if ATP has its own bug reporting process.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    Thursday, May 23, 2013 2:30 PM
    Moderator
  • I don't still get how GetType() not working properly would be caused by bug in another library (which ATP simply is) unless there really is a bug in GetType() itself.

    Async feature relies only on C#-compiler doing some "magic" (building state machine and additional types, nothing you couldn't do in plain C#-code) and some changes to framework libraries (e.g. new interfaces and implementations for these interfaces). ATP is simply a library which provides these interfaces and implementations and it could be hand-coded in plain C# (as Jon Skeet demonstrates http://msmvps.com/blogs/jon_skeet/archive/tags/Eduasync/default.aspx).

    Doesn't this suggest that I could write plain C# application without actual async/await keywords with C# 5.0 targeting .NET v4.0 which would still cause GetType() to behave improperly?

    Anyway you're right that this issue should be reported to MS. I guess I'll try Connect first.

    Thanks!



    • Edited by Jack Arete Thursday, May 23, 2013 2:48 PM typo
    Thursday, May 23, 2013 2:47 PM
  • It's possible the problem lies with the version of the assemblies you are loading. I ran into a problem with GetTypes hanging indefinitely on certain assemblies, and discovered it was because those assemblies, though they were built for 4.0, had references to assemblies built on .NET 2.0 and earlier. I solved the problem by inserting the following into the app.config:

      <startup useLegacyV2RuntimeActivationPolicy="true">
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
      </startup>

    Saturday, December 14, 2013 1:02 AM