docs/error-messages/compiler-warnings/compiler-warnings-by-compiler-version.md:699:| C4747 | `Calling managed 'type': Managed code may not be run under loader lock, including the DLL entrypoint and calls reached from the DLL entrypoint` |
docs/error-messages/compiler-warnings/compiler-warning-level-1-c4747.md:11:Calling managed 'entrypoint': Managed code may not be run under loader lock, including the DLL entrypoint and calls reached from the DLL entrypoint
docs/error-messages/compiler-warnings/compiler-warnings-c4600-through-c4799.md:138:|[Compiler warning (level 1) C4747](../../error-messages/compiler-warnings/compiler-warning-level-1-c4747.md)|Calling managed 'entrypoint': Managed code may not be run under loader lock, including the DLL entrypoint and calls reached from the DLL entrypoint|
docs/error-messages/tool-errors/c-runtime-error-r6031.md:25:This diagnostic indicates that MSIL instructions were executing during loader lock. For more information, see [Initialization of Mixed Assemblies](../../dotnet/initialization-of-mixed-assemblies.md).
docs/error-messages/tool-errors/c-runtime-error-r6033.md:25:This diagnostic indicates that MSIL instructions were executing during loader lock. This can occur if you have compiled native C++ by using the /clr flag. Only use the /clr flag on modules that contain managed code. For more information, see [Initialization of Mixed Assemblies](../../dotnet/initialization-of-mixed-assemblies.md).
docs/dotnet/how-to-migrate-to-clr.md:108:### Loader lock deadlock
docs/dotnet/how-to-migrate-to-clr.md:110:The "loader lock deadlock" can occur, but is deterministic and is detected and reported at runtime. See [Initialization of Mixed Assemblies](../dotnet/initialization-of-mixed-assemblies.md) for detailed background, guidance, and solutions.
docs/dotnet/library-support-for-mixed-assemblies.md:29:- Resolves the loader lock issues that applied to mixed DLLs compiled in Visual Studio 2003 and earlier.
docs/dotnet/initialization-of-mixed-assemblies.md:5:helpviewer_keywords: ["mixed assemblies [C++], loader lock", "loader lock [C++]", "initializing mixed assemblies", "deadlocks [C++]", ".cctor [C++]", "custom locales [C++]", "mixed assemblies [C++], initilizing"]
docs/dotnet/initialization-of-mixed-assemblies.md:10:Windows developers must always be wary of loader lock when running code during `DllMain`. However, there are some additional issues to consider when dealing with C++/CLI mixed-mode assemblies.
docs/dotnet/initialization-of-mixed-assemblies.md:14:## Causes of Loader Lock
docs/dotnet/initialization-of-mixed-assemblies.md:20:The Windows loader guarantees that no code can access code or data in that DLL before it's been initialized. And it ensures that no code can redundantly load the DLL while it's partially initialized. To do it, the Windows loader uses a process-global critical section (often called the "loader lock") that prevents unsafe access during module initialization. As a result, the loading process is vulnerable to many classic deadlock scenarios. For mixed assemblies, the following two scenarios increase the risk of deadlock:
docs/dotnet/initialization-of-mixed-assemblies.md:22:- First, if users attempt to execute functions compiled to Microsoft intermediate language (MSIL) when the loader lock is held (from `DllMain` or in static initializers, for example), it can cause deadlock. Consider the case in which the MSIL function references a type in an assembly that's not loaded yet. The CLR will attempt to automatically load that assembly, which may require the Windows loader to block on the loader lock. A deadlock occurs, since the loader lock is already held by code earlier in the call sequence. However, executing MSIL under loader lock doesn't guarantee that a deadlock will occur. That's what makes this scenario difficult to diagnose and fix. In some circumstances, such as when the DLL of the referenced type contains no native constructs and all of its dependencies contain no native constructs, the Windows loader isn't required to load the .NET assembly of the referenced type. Additionally, the required assembly or its mixed native/.NET dependencies may have already been loaded by other code. Consequently, the deadlocking can be difficult to predict, and can vary depending on the configuration of the target machine.
docs/dotnet/initialization-of-mixed-assemblies.md:24:- Second, when loading DLLs in versions 1.0 and 1.1 of the .NET Framework, the CLR assumed that the loader lock wasn't held, and took several actions that are invalid under loader lock. Assuming that the loader lock isn't held is a valid assumption for purely .NET DLLs. But because mixed DLLs execute native initialization routines, they require the native Windows loader, and consequently the loader lock. So, even if the developer wasn't attempting to execute any MSIL functions during DLL initialization, there was still a small possibility of nondeterministic deadlock in .NET Framework versions 1.0 and 1.1.
docs/dotnet/initialization-of-mixed-assemblies.md:32:Loader lock can still occur, but now it occurs reproducibly, and is detected. If `DllMain` contains MSIL instructions, the compiler generates warning [Compiler Warning (level 1) C4747](../error-messages/compiler-warnings/compiler-warning-level-1-c4747.md). Furthermore, either the CRT or the CLR will try to detect and report attempts to execute MSIL under loader lock. CRT detection results in runtime diagnostic C Run-Time Error R6033.
docs/dotnet/initialization-of-mixed-assemblies.md:34:The rest of this article describes the remaining scenarios for which MSIL can execute under the loader lock. It shows how to resolve the issue under each of those scenarios, and debugging techniques.
docs/dotnet/initialization-of-mixed-assemblies.md:38:There are several different situations under which user code can execute MSIL under loader lock. The developer must ensure that the user code implementation doesn't attempt to execute MSIL instructions under each of these circumstances. The following subsections describe all possibilities with a discussion of how to resolve issues in the most common cases.
docs/dotnet/initialization-of-mixed-assemblies.md:42:The `DllMain` function is a user-defined entry point for a DLL. Unless the user specifies otherwise, `DllMain` is invoked every time a process or thread attaches to or detaches from the containing DLL. Since this invocation can occur while the loader lock is held, no user-supplied `DllMain` function should be compiled to MSIL. Furthermore, no function in the call tree rooted at `DllMain` can be compiled to MSIL. To resolve issues here, the code block that defines `DllMain` should be modified with `#pragma unmanaged`. The same should be done for every function that `DllMain` calls.
docs/dotnet/initialization-of-mixed-assemblies.md:46:As an alternative, if `DllMain` isn't required or if it doesn't need to be executed under loader lock, you can remove the user-provided `DllMain` implementation, which eliminates the problem.
docs/dotnet/initialization-of-mixed-assemblies.md:65:This risk of deadlock depends on whether the containing module is compiled with **`/clr`** and whether MSIL will be executed. Specifically, if the static variable is compiled without **`/clr`** (or is in a `#pragma unmanaged` block), and the dynamic initializer required to initialize it results in the execution of MSIL instructions, deadlock may occur. It's because, for modules compiled without **`/clr`**, the initialization of static variables is performed by DllMain. In contrast, static variables compiled with **`/clr`** are initialized by the `.cctor`, after the unmanaged initialization stage has completed and the loader lock has been released.
docs/dotnet/initialization-of-mixed-assemblies.md:79:If the user-provided versions are compiled to MSIL, then these initializers will be attempting to execute MSIL instructions while the loader lock is held. A user-supplied `malloc` has the same consequences. To resolve this problem, any of these overloads or user-supplied definitions must be implemented as native code using the `#pragma unmanaged` directive.
docs/dotnet/initialization-of-mixed-assemblies.md:85:If the user provides a custom global locale, this locale gets used to initialize all future I/O streams, including streams that are statically initialized. If this global locale object is compiled to MSIL, then locale-object member functions compiled to MSIL may be invoked while the loader lock is held.
docs/dotnet/initialization-of-mixed-assemblies.md:89:The source files containing all global I/O stream definitions can be compiled using the **`/clr`** option. It prevents their static initializers from being executed under loader lock.
docs/dotnet/initialization-of-mixed-assemblies.md:93:Refrain from setting the custom locale as the global locale until after the loader lock is released. Then explicitly configure I/O streams created during initialization with the custom locale.
docs/dotnet/initialization-of-mixed-assemblies.md:105:Because the same header may be included both by C++ files with **`/clr`** enabled and disabled, or a #include can be wrapped inside a `#pragma unmanaged` block, it's possible to have both MSIL and native versions of functions that provide implementations in headers. MSIL and native implementations have different semantics for initialization under the loader lock, which effectively violates the one definition rule. Consequently, when the linker chooses the largest implementation, it may choose the MSIL version of a function, even if it was explicitly compiled to native code elsewhere using the `#pragma unmanaged` directive. To ensure that an MSIL version of a template or inline function is never called under loader lock, every definition of every such function called under loader lock must be modified with the `#pragma unmanaged` directive. If the header file is from a third party, the easiest way to make this change is to push and pop the `#pragma unmanaged` directive around the #include directive for the offending header file. (See [managed, unmanaged](../preprocessor/managed-unmanaged.md) for an example.) However, this strategy doesn't work for headers that contain other code that must directly call .NET APIs.
docs/dotnet/initialization-of-mixed-assemblies.md:107:As a convenience for users dealing with loader lock, the linker will choose the native implementation over the managed when presented with both. This default avoids the above issues. However, there are two exceptions to this rule in this release because of two unresolved issues with the compiler:
docs/dotnet/initialization-of-mixed-assemblies.md:131:All diagnoses of loader lock problems should be done with Debug builds. Release builds may not produce diagnostics. And, the optimizations made in Release mode may mask some of the MSIL under loader lock scenarios.
docs/dotnet/initialization-of-mixed-assemblies.md:133:## How to debug loader lock issues
docs/dotnet/initialization-of-mixed-assemblies.md:137:To identify the specific MSIL function that was called under loader lock, developers should complete the following steps:
docs/dotnet/initialization-of-mixed-assemblies.md:161:1. Look for the first instance (closest to the bottom of the stack) of either _CorDllMain (if `DllMain` causes the issue) or _VTableBootstrapThunkInitHelperStub or GetTargetForVTableEntry (if a static initializer causes the issue). The stack entry just below this call is the invocation of the MSIL implemented function that attempted to execute under loader lock.
docs/dotnet/initialization-of-mixed-assemblies.md:169:The following sample shows how to avoid loader lock by moving code from `DllMain` into the constructor of a global object.
docs/dotnet/mixed-native-and-managed-assemblies.md:27:Describes the "loader lock" problem and solutions.
