Freigeben über


Loader lock issue in mixed mode application

ISSUE:  

I am back with another mixed-mode situation. An issue may happen when the native class constructor calls a managed function. 

For example, Let us say we have a C# application which is calling a C++ DLL using DLL Import attribute. The C++ DLL has a class whose constructor initializes a few variables and also calls a managed function. This may lead to loader lock issue.

CAUSE:

Let us see why this issue may happen. There are two distinct mechanisms for loading an execution module (EXE or DLL):

1) One for Windows, which is used for unmanaged modules,

2) One for the .NET Common Language Runtime (CLR) which loads managed assemblies.

When an assembly containing only .NET constructs is loaded into a process, the CLR loader can perform all of the necessary loading and initialization tasks itself. However, for mixed assemblies, because they can contain native code and data, the Windows loader must also be used.

The Windows loader guarantees that no code can access code or data in that DLL before it has been initialized, and that no code can redundantly load the DLL while it is partially initialized. To do this, the Windows loader uses a process-global critical section (often called the "loader lock") that prevents unsafe access during module initialization.

If we attempt to execute managed functions when this loader lock is held, the CLR will attempt to automatically load the managed assembly, which may require the Windows loader to block on the loader lock. Since the loader lock is already held by code earlier in the call sequence, a deadlock results. However, it is possible that the required managed assembly has already been successfully loaded by other code. In that case, the deadlock will not happen. This makes this scenario difficult to diagnose and fix as the situation does not guarantee that a deadlock will happen.

 

RESOLUTION:  

So to avoid this problem, we should make sure that the native constructor doesn’t have any managed function call. We can call that managed function outside the constructor which lets the native DLL to get initialized successfully.

Thumb Rule:

Do NOT call a managed function in constructor of an unmanaged class.